Fitur bahasa Java 7 dengan Android

188

Hanya ingin tahu apakah ada yang sudah mencoba menggunakan fitur Java 7 baru dengan Android? Saya tahu bahwa Android membaca bytecode yang dimuntahkan Java dan mengubahnya menjadi dex. Jadi saya kira pertanyaan saya adalah dapatkah ia memahami bytecode Java 7?

Daniel Ryan
sumber
10
Atau, mungkin Anda dapat menggunakan fitur bahasa Java 7 tetapi mengkompilasi bytecode Java 6?
MatrixFrog
2
Android Studio sekarang akan memberi Anda pemberitahuan saat membuat proyek baru: "Dengan minSdkVersion kurang dari 19, Anda tidak dapat menggunakan coba-dengan-sumber daya, tetapi fitur bahasa Java 7 lainnya baik-baik saja"
IgorGanapolsky
1
Ya saya tahu :) Kami akhirnya menggunakan Java 7 dalam proyek kami.
Daniel Ryan

Jawaban:

165

Jika Anda menggunakan Android Studio , Jawa 7 bahasa harus diaktifkan secara otomatis tanpa patch. Try-with-resource membutuhkan API Level 19+, dan NIO 2.0 tidak ada.

Jika Anda tidak dapat menggunakan fitur Java 7, lihat jawaban @Nuno tentang cara mengedit build.gradle.

Berikut ini hanya untuk kepentingan historis.


Sebagian kecil Java 7 tentu dapat digunakan dengan Android (catatan: Saya baru menguji pada 4.1).

Pertama-tama, Anda tidak bisa menggunakan ADT Eclipse karena hard-coded yang hanya memenuhi kompiler Java 1.5 dan 1.6. Anda dapat mengkompilasi ulang ADT tetapi saya menemukan tidak ada cara sederhana untuk melakukannya selain mengkompilasi ulang seluruh Android bersama-sama.

Tetapi Anda tidak perlu menggunakan Eclipse. Misalnya, Android Studio 0.3.2 , IntelliJ IDEA CE dan IDE berbasis javac lainnya mendukung kompilasi ke Android dan Anda dapat mengatur kepatuhan bahkan hingga Java 8 dengan:

  • File → Struktur Proyek → Modul → (pilih modul pada panel ke-2) → Level bahasa → (pilih "7.0 - Berlian, ARM, multi-tangkapan, dll.")

Mengaktifkan Java 7 di IntelliJ

Ini hanya memungkinkan fitur bahasa Java 7 , dan Anda hampir tidak dapat mengambil manfaat dari apa pun karena setengah dari perbaikan juga berasal dari perpustakaan. Fitur yang dapat Anda gunakan adalah yang tidak bergantung pada perpustakaan:

  • Operator berlian ( <>)
  • Switch string
  • Multiple-catch ( catch (Exc1 | Exc2 e))
  • Garis bawah dalam literal angka ( 1_234_567)
  • Literary biner (0b1110111 )

Dan fitur-fitur ini tidak dapat digunakan lagi :

  • Pernyataan try-dengan-sumber daya - karena memerlukan antarmuka yang tidak ada "java.lang.AutoCloseable" (ini dapat digunakan untuk umum di 4.4+)
  • Anotasi @SafeVarargs - karena "java.lang.SafeVarargs" tidak ada

... "yet" :) Ternyata, meskipun perpustakaan Android menargetkan untuk 1.6, sumber Android memang mengandung antarmuka seperti AutoCloseable dan antarmuka tradisional seperti Closeable memang mewarisi dari AutoCloseable (SafeVarargs benar-benar hilang, meskipun). Kami bisa mengkonfirmasi keberadaannya melalui refleksi. Mereka disembunyikan hanya karena Javadoc memiliki@hide tag, yang menyebabkan "android.jar" tidak memasukkan mereka.

Sudah ada pertanyaan yang sudah ada Bagaimana cara membangun Android SDK dengan API internal dan tersembunyi tersedia? tentang cara mendapatkan metode tersebut kembali. Anda hanya perlu mengganti referensi "android.jar" yang ada dari Platform saat ini dengan yang kami sesuaikan, maka banyak Java 7 API akan tersedia (prosedurnya mirip dengan yang ada di Eclipse. Periksa Struktur Proyek → SDK.)

Selain AutoCloseable, (hanya) fitur Java 7 library berikut juga terungkap:

  • Konstruktor perangkaian pengecualian di ConcurrentModificationException, LinkageError, dan AssertionError
  • Metode .compare () statis untuk primitif: Boolean.compare (), Byte.compare (), Short.compare (), Character.compare (), Integer.compare (), Integer.compare (), Long.compare ().
  • Mata uang : .getAvailableCurrency (), .getDisplayName () (tetapi tanpa .getNumericCode ())
  • BitSet : .previousSetBit (), .previousClearBit (), .valueOf (), .toLongArray (), .toByteArray ()
  • Koleksi : .emptyEnumeration (), .emptyIterator (), .emptyListIterator ()
  • Dapat Ditutup Otomatis
  • Throwable : .addSuppressed (), .getSuppressed (), dan konstruktor 4-argumen
  • Karakter : .compare (), .isSurrogate (), .getName (), .highSurrogate (), .lowSurrogate (), .isBmpCodePoint () (tetapi tanpa .isAlphabetic () dan .isIdeographic ())
  • Sistem: .lineSeparator () (tidak berdokumen?)
  • java.lang.reflect.Modifier : .classModifiers (), .constructorModifiers (), .fieldModifiers (), .interfaceModifiers (), .methodModifiers ()
  • NetworkInterface : .getIndex (), .getByIndex ()
  • InetSocketAddress : .getHostString ()
  • InetAddress : .getLoopbackAddress ()
  • Logger : .getGlobal ()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer : .hasQueuedPredecessors ()
  • DeflaterOutputStream : 3 konstruktor dengan "syncFlush".
  • Deflater : .NO_FLUSH, .SYNC_FLUSH, .FULL_FLUSH, .deflate () dengan 4 argumen

Itu pada dasarnya semua. Secara khusus, NIO 2.0 tidak ada, dan Arrays.asList masih belum @SafeVarargs.

kennytm
sumber
2
Jawaban yang bagus Saya berharap dukungan penuh level akan segera terjadi di masa depan, nio2dan barang lainnya pasti akan menjadi kabar baik.
SD
4
Patut disebutkan bahwa AutoCloseableantarmuka tidak ada di Android runtime sampai ICS (atau mungkin sampai HoneyComb). Jadi, bahkan jika Anda menggunakan tambalan android.jar Anda akan menerima NoClassDefFoundErrorpada sistem 2.x.
Idolon
2
@deviant: Itu memerlukan modifikasi Dalvik VM, karena Java 8 lambda menggunakan invokedynamicyang tidak didukung oleh JVM yang menargetkan Java 6.
kennytm
2
Anda mungkin ingin menambahkan pembaruan bahwa pada Android studio 3.2, Level bahasa 7 didukung sepenuhnya, seperti halnya coba-dengan-sumber daya jika Anda mengompilasi melawan KitKat
JRaymond
4
coba dengan sumber daya sekarang dapat digunakan di SDK 19 (Android Kitkat). lihat tools.android.com/recent/androidstudio032released
Mohamed El-Nakib
70

EDIT: Pada saat ini ditulis, rilis terbaru adalah Android 9 dan Eclipse Indigo. Hal telah berubah sejak saat itu.

  • Jawaban praktis

Ya, saya sudah mencoba. Tapi ini bukan tes yang bagus karena kompatibilitasnya terbatas pada level 6 tanpa cara (setidaknya tidak ada cara sederhana) untuk benar-benar menggunakan java 7:

  • Pertama saya menginstal JDK7 pada mesin yang tidak memiliki JDK lain yang diinstal - Eclipse dan Android juga tidak diinstal:

7 adalah satu-satunya yang diinstal pada mesin ini

  • Kemudian saya memasang Eclipse Indigo yang baru dan memeriksa apakah itu benar-benar menggunakan JDK 7 (yah, karena ini adalah satu-satunya dan karena ini adalah yang saya pilih, saya akan terkejut)

7 adalah satu-satunya yang digunakan oleh Eclipse ini

  • Kemudian saya menginstal Android SDK versi terbaru (EDIT: Honeycomb, API13, pada saat tulisan ini ditulis). Ia menemukan JDK 7 saya dan diinstal dengan benar. Sama untuk ADT.

  • Tapi saya terkejut ketika mencoba mengkompilasi dan menjalankan aplikasi Hello Word Android. Kompatibilitas diatur ke Java 6 tanpa ada cara untuk memaksanya ke Java 7:

Kompatibilitas terbatas pada Java 6

  • Saya mencoba dengan proyek non-Android, yang Java biasa, dan saya punya penjelasan. Tingkat kompatibilitas tampaknya dibatasi oleh Eclipse (lihat pesan di bawah gambar berikut):

Eclipse membatasi dirinya ke kompatibilitas level 6

Jadi saya punya Hello World bekerja, dan juga aplikasi lain yang lebih rumit dan menggunakan SQLite, Listview, Sensordan Camera, tapi ini hanya membuktikan bahwa kompatibilitas penanganan Jawa 7 tampaknya harus dilakukan dengan baik dan bekerja dengan Android.

Jadi, apakah seseorang mencoba dengan semut tua yang baik, untuk melewati batasan Eclipse yang terlihat di atas?

  • Jawaban theroetis

Bagaimanapun, SDK dirancang untuk digunakan dengan Java 5 atau 6, seperti yang dijelaskan sini .

Kami mungkin memiliki sesuatu yang bekerja dengan Java 7, tetapi itu akan berfungsi "secara tidak sengaja". Bangunan DEX dapat berfungsi dengan baik atau tidak, dan begitu DEX dibangun, mungkin berhasil atau tidak. Ini karena menggunakan JDK yang tidak memenuhi syarat memberikan hasil yang tidak terduga menurut definisi.

Bahkan jika seseorang telah berhasil membangun aplikasi Android di bawah Java 7, ini tidak memenuhi syarat JDK. Proses yang sama yang diterapkan pada aplikasi lain mungkin gagal, atau aplikasi yang dihasilkan mungkin memiliki bug yang terkait dengan penggunaan JDK itu. Tidak direkomendasikan.

Bagi mereka yang terlibat dalam pengembangan webapps, ini persis sama dengan menyebarkan aplikasi web yang dibangun di bawah Java 5 atau 6 di bawah server aplikasi yang memenuhi syarat untuk Java 4 saja (katakanlah misalnya Weblogic 8 misalnya). Ini mungkin berhasil, tetapi ini bukan sesuatu yang dapat direkomendasikan untuk tujuan lain selain mencoba.

Shlublu
sumber
1
Terima kasih untuk ulasan terperinci itu. Jadi sepertinya Anda tidak dapat menggunakan fitur bahasa Java 7 tetapi masih menggunakan Java 7 sebagai Java 6. Mudah-mudahan ini segera berubah :)
Daniel Ryan
Ini dengan Eclipse. Dengan Semut, ini mungkin terjadi. Saya harap seseorang akan melakukan tes dan saya menyalahkan diri sendiri karena terlalu malas untuk melakukannya :)
Shlublu
Ya Varga, tapi saya tidak berpikir keterbatasan versi kompiler berasal dari Ant tetapi dari Eclipse.
Shlublu
2
Juga perhatikan bahwa jika Anda bermain-main dengan beberapa versi Java, alat yang disediakan tidak kompatibel. Maksud saya adalah bahwa jika Anda pertama kali menandatangani aplikasi Anda dengan jarsigner dari alat java 6 dan kemudian menginstal java 7 dan menandatangani versi baru aplikasi kami dengan jarsigner yang datang dengan java 7 dan keystore yang sama seperti sebelumnya tanda tangan tidak akan cocok !
Timo
38

Kutipan dari dalvikvm.com:

dx, termasuk dalam Android SDK, mentransformasikan file Java Class dari kelas Java yang dikompilasi oleh Java compiler biasa menjadi format file kelas lain (format .dex)

Itu berarti, file sumber .java tidak masalah, itu hanya bytecode .class.

Sejauh yang saya tahu, hanya invokedynamic yang ditambahkan ke bytecode JVM di Java 7, sisanya kompatibel dengan Java 6. Bahasa Java sendiri tidak menggunakan invokedynamic . Fitur baru lainnya, seperti pernyataan switch menggunakan String s atau multi- catch hanyalah gula sintaksis dan tidak memerlukan perubahan kode byte. Sebagai contoh, multi- catch hanya menyalin catch -block untuk setiap kemungkinan pengecualian.

Satu-satunya masalah adalah bahwa kelas-kelas baru yang diperkenalkan di Java 7 hilang di Android, seperti AutoCloseable , jadi saya tidak yakin apakah Anda dapat menggunakan fitur try -with-resources (seseorang mencobanya?).

Ada komentar tentang itu? Apakah saya melewatkan sesuatu?

Dan saya
sumber
2
Sekarang masalahnya adalah bagaimana kita mengkonfigurasi kode sumber Java 7 yang dikompilasi ke file kelas Java 6, terutama di eclipse?
Randy Sugianto 'Yuku'
Satu-satunya pertanyaan yang tersisa adalah mengapa Anda repot-repot?
Warpzit
@ Warpzit pertanyaan yang lebih besar adalah Mengapa seorang pengembang tidak akan repot untuk semua kebingungan ini?
Amit
@Amit karena dia menyadari Android berbeda dari Java dan untuk bekerja dengan Android dia harus menggunakan alat yang ditawarkan.
Warpzit
2
@Warpzit Satu-satunya pertanyaannya adalah " Bisakah Android memahami java 7? " Ketidaktahuan tidak pernah menjadi solusi / jawaban ...
Amit
12

Pada Android SDK v15, bersama dengan Eclipse 3.7.1, Java 7 tidak didukung untuk pengembangan Android. Mengatur kompatibilitas sumber ke 1,7 mandat pengaturan kompatibilitas file .class yang dihasilkan ke 1,7, yang mengarah ke kesalahan berikut oleh kompiler Android:

Android membutuhkan kepatuhan kompiler level 5.0 atau 6.0. Ditemukan '1,7' sebagai gantinya. Silakan gunakan Alat Android> Perbaiki Properti Proyek.

Hosam Aly
sumber
5

Untuk memperluas jawaban di atas oleh @ KennyTM, jika Anda menargetkan 4.0.3 dan lebih tinggi ( minSdkVersion = 15 ), Anda dapat menggunakan API tersembunyi dengan menambahkan beberapa kelas ke SDK android.jar target Anda.

Setelah Anda melakukan ini, Anda dapat menggunakan coba-dengan-sumber daya pada Closeable apa pun, serta menerapkan AutoCloseable di kelas Anda sendiri.

Saya telah membuat zip yang berisi sumber dan binari dari semua kelas yang perlu dimodifikasi di android.jar untuk membuat API ini tersedia. Anda hanya perlu membongkar dan menambahkan binari ke
android-SDK / platform / Android-NN / Android.jar Anda

Anda dapat mengunduhnya dari sini: http://db.tt/kLxAYWbr

Yang juga perlu diperhatikan adalah bahwa, dalam beberapa bulan terakhir, Elliott Hughes telah membuat beberapa komitmen pada pohon Android: menghabisi AutoCloseable , menambahkan SafeVarargs , menambah berbagai API , memperbaiki konstruktor yang dilindungi Throwable dan menambahkan dukungan untuk file kelas versi 51 di dx . Jadi, akhirnya ada beberapa kemajuan yang terjadi.

Edit (April 2014):

Dengan dirilisnya SDK 19, Anda tidak perlu lagi menambal android.jar dengan API tambahan.

Metode terbaik untuk menggunakan coba-dengan-sumber daya di Android Studio untuk aplikasi yang menargetkan 4.0.3 dan di atasnya ( minSdkVersion = 15 ) adalah menambahkan yang berikut compileOptionske build.gradle:

android {
    compileSdkVersion 19
    buildToolsVersion '19.0.3'

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 19
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
}

Android Studio akan mengeluh bahwa coba-dengan-sumber daya tidak dapat digunakan dengan level API ini, tetapi pengalaman saya adalah bahwa hal itu bisa. Proyek ini akan dibangun dan dijalankan tanpa masalah pada perangkat dengan 4.0.3 dan lebih tinggi. Saya tidak mengalami masalah dengan ini, dengan aplikasi yang telah diinstal ke perangkat 500k +.

Kesalahan Android Studio

Untuk mengabaikan peringatan ini, tambahkan yang berikut ke lint.xml:

<issue id="NewApi">
    <ignore regexp="Try-with-resources requires API level 19"/>
</issue>
Nuno Cruces
sumber
1
Saya merasa menarik bahwa peringatan kode Android Studio mengatakan coba-dengan-sumber daya baru di API 13 dan saya harus menggunakannya. Meskipun tidak punya waktu untuk benar-benar menguji apakah itu berfungsi dengan benar.
Daniel Ryan
1

Tampaknya membuat ini berfungsi dengan semut murni adalah sedikit omong kosong.

Tapi itu berhasil untuk saya: http://www.informit.com/articles/article.aspx?p=1966024

mako
sumber
1
Saya mencari ini untuk waktu yang lama. Untuk mengurangi masalah orang melalui pemfilteran artikel, Anda harus mengubah baris `<property name =" java.source "value =" 1.5 "/>` di build.xml yang disediakan oleh android (bukan yang ada di Android). proyek Anda!). Bagi saya itu di /opt/android-sdk-update-manager/tools/ant/build.xml
Mateusz Kowalczyk
Tidak, kamu tidak. Anda dapat menimpa properti tersebut dengan custom_rules.xml, lihat jawaban saya di sini: stackoverflow.com/a/24608415/194894
Flow
1

Untuk menggunakan fitur Java 7 dalam kode build oleh sistem build berbasis semut Android, cukup masukkan yang berikut ini di custom_rules.xmldalam direktori root proyek Anda:

custom_rules.xml:

<project name="custom_android_rules">
    <property name="java.target" value="1.7" />
    <property name="java.source" value="1.7" />
</project>
Mengalir
sumber
0

Beberapa orang mungkin tertarik dengan proyek git yang saya temukan ini, yang sepertinya memungkinkan untuk menjalankan Java 7 di android. https://github.com/yareally/Java7-on-Android

Namun terlalu banyak risiko jika saya menambahkan ini di proyek saat ini saya kerjakan. Jadi saya akan menunggu sampai Google secara resmi mendukung Java 7.

Daniel Ryan
sumber