Funzionalità del linguaggio Java 7 con Android


188

Ti stai solo chiedendo se qualcuno ha provato a utilizzare le nuove funzionalità del linguaggio Java 7 con Android? So che Android legge il bytecode che Java sputa e lo trasforma in dex. Quindi immagino che la mia domanda sia: può capire il bytecode di Java 7?


10
In alternativa, forse puoi usare le funzionalità del linguaggio Java 7 ma compilare in bytecode Java 6?
MatrixFrog,

2
Android Studio ora ti darà una notifica durante la creazione di un nuovo progetto: "Con minSdkVersion meno di 19, non puoi usare try-with-resources, ma altre funzionalità del linguaggio Java 7 vanno bene"
IgorGanapolsky

1
Sì, lo so :) Stiamo finalmente usando Java 7 nel nostro progetto.
Daniel Ryan,

Risposte:


165

Se si utilizza Android Studio , la lingua Java 7 deve essere abilitata automaticamente senza patch. Try-with-resource richiede API Level 19+ e mancano elementi NIO 2.0.

Se non puoi usare le funzionalità di Java 7, vedi la risposta di @Nuno su come modificare il tuo build.gradle.

Quanto segue è solo per interesse storico.


Una piccola parte di Java 7 può certamente essere utilizzata con Android (nota: ho testato solo su 4.1).

Prima di tutto, non è stato possibile utilizzare l'ADT di Eclipse perché è codificato che solo i compilatori Java 1.5 e 1.6 sono conformi. Potresti ricompilare ADT ma trovo che non ci sia un modo semplice per farlo oltre a ricompilare l'intero Android insieme.

Ma non è necessario utilizzare Eclipse. Ad esempio, Android Studio 0.3.2 , IntelliJ IDEA CE e altri IDE basati su javac supportano la compilazione su Android e si potrebbe impostare la conformità fino a Java 8 con:

  • File → Struttura del progetto → Moduli → (seleziona il modulo nel secondo riquadro) → Livello lingua → (scegli "7.0 - Diamanti, ARM, multi-catch, ecc.")

Abilitazione di Java 7 su IntelliJ

Ciò consente solo le funzionalità del linguaggio Java 7 e difficilmente si può trarre vantaggio da qualsiasi cosa, dal momento che la metà del miglioramento proviene anche dalla libreria. Le funzionalità che è possibile utilizzare sono quelle che non dipendono dalla libreria:

  • Operatore Diamond ( <>)
  • Interruttore di stringa
  • Cattura multipla ( catch (Exc1 | Exc2 e))
  • Sottolineatura in numeri letterali ( 1_234_567)
  • Letterali binari ( 0b1110111)

E queste caratteristiche non possono essere utilizzate ancora :

  • L' tryistruzione -with-resources - perché richiede l'interfaccia inesistente "java.lang.AutoCloseable" (può essere utilizzata pubblicamente in 4.4+)
  • L'annotazione @SafeVarargs - perché "java.lang.SafeVarargs" non esiste

... "ancora" :) Si scopre che, sebbene la libreria di Android abbia come target 1.6, la fonte Android contiene interfacce come AutoCloseable e interfacce tradizionali come Closeable eredita da AutoCloseable (SafeVarargs è davvero mancante). Potremmo confermare la sua esistenza attraverso la riflessione. Sono nascosti semplicemente perché Javadoc ha il @hidetag, che ha fatto sì che "android.jar" non li includesse.

Esiste già una domanda esistente: come faccio a creare l'SDK Android con le API nascoste e interne disponibili? su come recuperare quei metodi. Devi solo sostituire il riferimento "android.jar" esistente della piattaforma attuale con quello personalizzato, quindi molte delle API Java 7 saranno disponibili (la procedura è simile a quella di Eclipse. Verifica struttura del progetto → SDK).

Oltre a AutoCloseable, vengono rivelate (solo) le seguenti funzionalità della libreria Java 7 :

  • Costruttori di concatenamento di eccezioni in ConcurrentModificationException, LinkageError e AssertionError
  • I metodi statici .compare () per le primitive: Boolean.compare (), Byte.compare (), Short.compare (), Character.compare (), Integer.compare (), Long.compare ().
  • Valuta : .getAvailableCurrencies (), .getDisplayName () (ma senza .getNumericCode ())
  • BitSet : .previousSetBit (), .previousClearBit (), .valueOf (), .toLongArray (), .toByteArray ()
  • Collezioni : .emptyEnumeration (), .emptyIterator (), .emptyListIterator ()
  • AutoCloseable
  • Throwable : .addSuppressed (), .getSuppressed () e il costruttore a 4 argomenti
  • Carattere : .compare (), .isSurrogate (), .getName (), .highSurrogate (), .lowSurrogate (), .isBmpCodePoint () (ma senza .isAlphabetic () e .isIdeographic ())
  • Sistema: .lineSeparator () (non documentato?)
  • java.lang.reflect.Modifier : .classModifiers (), .constructorModifiers (), .fieldModifiers (), .interfaceModifiers (), .methodModifiers ()
  • Interfaccia di rete : .getIndex (), .getByIndex ()
  • InetSocketAddress : .getHostString ()
  • InetAddress : .getLoopbackAddress ()
  • Registratore : .getGlobal ()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer : .hasQueuedPredecessors ()
  • DeflaterOutputStream : i 3 costruttori con "syncFlush".
  • Deflater : .NO_FLUSH, .SYNC_FLUSH, .FULL_FLUSH, .deflate () con 4 argomenti

Questo è praticamente tutto. In particolare, NIO 2.0 non esiste e Arrays.asList non è ancora @SafeVarargs.


2
Bella risposta. Spero che il pieno supporto a livello jvm accadrà presto in futuro nio2e altre chicche saranno sicuramente una buona notizia.
SD

4
Vale la pena ricordare che l' AutoCloseableinterfaccia non esiste nel runtime di Android fino a ICS (o forse fino a HoneyComb). Quindi anche se usi android.jar con patch riceverai NoClassDefFoundErrorsul sistema 2.x.
Idolon

2
@deviant: questo richiede la modifica della VM Dalvik, poiché Java 8 lambda utilizza invokedynamicche non è supportato dalla JVM destinata a Java 6.
kennytm

2
Potresti voler aggiungere un aggiornamento che a partire da Android Studio 3.2, Livello di lingua 7 è completamente supportato, così come prova con le risorse se stai compilando con KitKat
JRaymond

4
provare con le risorse ora può essere utilizzato su SDK 19 (Android Kitkat). vedi tools.android.com/recent/androidstudio032released
Mohamed El-Nakib

70

EDIT: Al momento in cui è stato scritto, l'ultima versione era Android 9 ed Eclipse Indigo. Le cose sono cambiate da allora.

  • Risposta pratica

Sì, ci ho provato. Ma questo non è un ottimo test in quanto la compatibilità era limitata al livello 6 senza alcun modo (almeno un modo semplice) di usare davvero Java 7:

  • Per prima cosa ho installato un JDK7 su un computer su cui non era installato nessun altro JDK - Eclipse e Android non sono installati:

Il 7 è l'unico installato su questa macchina

  • Quindi ho installato un nuovissimo Eclipse Indigo e ho verificato che stava effettivamente utilizzando il JDK 7 (beh, dato che questo è l'unico e poiché è quello che ho selezionato sarei stato sorpreso)

Il 7 è l'unico usato da questa Eclipse

  • Quindi ho installato l'ultima versione di Android SDK (EDIT: Honeycomb, API13, al momento in cui è stato scritto questo post). Ha trovato il mio JDK 7 e installato correttamente. Lo stesso per ADT.

  • Ma ho avuto una sorpresa quando ho provato a compilare ed eseguire un'app Android di Hello Word. La compatibilità è stata impostata su Java 6 senza alcun modo per forzarla su Java 7:

La compatibilità è limitata a Java 6

  • Ho provato con un progetto non Android, un normale Java, e ho avuto la spiegazione. Il livello di compatibilità sembra essere limitato da Eclipse (vedi il messaggio in fondo alla seguente immagine):

Eclipse si limita alla compatibilità di livello 6

Quindi ho avuto Hello World di lavoro, e anche altre applicazioni, più complicato e utilizzando SQLite, Listview, Sensore Camera, ma questo dimostra solo che la gestione di Java 7 compatibilità sembra essere ben fatto e lavorare con Android.

Quindi, qualcuno ha provato con la buona vecchia formica, per bypassare la limitazione di Eclipse vista sopra?

  • Risposta terapeutica

Comunque, l'SDK è progettato per essere utilizzato con Java 5 o 6, come spiegato qui .

Potremmo avere qualcosa che funziona con Java 7, ma funzionerebbe "per caso". La costruzione del DEX potrebbe funzionare correttamente o meno e, una volta creato il DEX, potrebbe funzionare o meno. Questo perché l'uso di un JDK non qualificato fornisce risultati imprevedibili per definizione.

Anche se qualcuno ha creato con successo un'app Android con Java 7, questo non qualifica JDK. Lo stesso processo applicato a un'altra applicazione potrebbe non riuscire o l'applicazione risultante potrebbe avere dei bug legati all'utilizzo di quel JDK. Non consigliato.

Per coloro che sono coinvolti nello sviluppo di webapps, ciò equivale esattamente alla distribuzione di un'applicazione Web creata in Java 5 o 6 in un server delle applicazioni qualificato solo per Java 4 (ad esempio Weblogic 8). Questo potrebbe funzionare, ma questo non è qualcosa che può essere raccomandato per scopi diversi dal provare.


1
Grazie per la recensione dettagliata. Quindi sembra che tu non possa usare le funzionalità del linguaggio Java 7 ma usi comunque Java 7 come Java 6. Speriamo che questo cambi presto :)
Daniel Ryan,

Questo è con Eclipse. Con Ant, questo è probabilmente possibile. Spero che qualcuno faccia il test e mi biasimo per essere troppo pigro per farlo :)
Shlublu,

Sì, Varga, ma non credo che la limitazione della versione del compilatore provenga da Ant ma da Eclipse.
Shlublu,

2
Si noti inoltre che se si gioca con più versioni di Java gli strumenti forniti non sono compatibili. Quello che voglio dire è che se prima firmassi la tua app con jarsigner dagli strumenti java 6 e successivamente hai installato java 7 e hai firmato una nuova versione della nostra app con il jarsigner fornito con java 7 e lo stesso keystore di prima le firme non corrispondevano !
Timo,

38

Citazione da dalvikvm.com:

dx, incluso in Android SDK, trasforma i file di classe Java delle classi Java compilati da un normale compilatore Java in un altro formato di file di classe (il formato .dex)

Ciò significa che il file sorgente .java non ha importanza, è solo il bytecode .class.

Per quanto ne so, solo il codice invocato è stato aggiunto al bytecode JVM in Java 7, il resto è compatibile con Java 6. Il linguaggio Java stesso non utilizza il metodo invokedynamic . Altre nuove funzionalità, come l' istruzione switch che utilizza String s o il multi- catch, sono solo zucchero sintetico e non richiedono modifiche al codice byte. Ad esempio, la cattura multipla copia solo la cattura catch per ogni possibile eccezione.

L'unico problema dovrebbe essere che le nuove classi introdotte in Java 7 mancano in Android, come AutoCloseable , quindi non sono sicuro se è possibile utilizzare il tentativo -with-resources (qualcuno l'ha provato?).

Qualche commento a riguardo? Mi sto perdendo qualcosa?


2
Ora il problema è come possiamo configurare in modo tale che i codici sorgente Java 7 vengano compilati in file di classe Java 6, specialmente in eclipse?
Randy Sugianto "Yuku",

L'unica domanda rimasta è: perché dovresti preoccuparti?
Warpzit,

@Warpzit la domanda più grande dovrebbe essere Perché uno sviluppatore non si preoccupi di tutta questa confusione?
Entro il

@Amit perché ha capito che Android è diverso da Java e per lavorare con Android deve usare gli strumenti offerti.
Warpzit,

2
@Warpzit La sua unica domanda è " Android può capire java 7? " L'ignoranza non è mai una soluzione / risposta ...
Entro il

12

A partire da Android SDK v15, insieme a Eclipse 3.7.1, Java 7 non è supportato per lo sviluppo Android. L'impostazione della compatibilità del sorgente su 1.7 richiede l'impostazione del compatibilità del file .class generato su 1.7, che porta al seguente errore da parte del compilatore Android:

Android richiede il livello di conformità del compilatore 5.0 o 6.0. Trovato invece '1.7'. Utilizza Strumenti Android> Correggi proprietà progetto.


5

Per espandere la risposta precedente di @KennyTM, se si sceglie come target 4.0.3 e versioni successive ( minSdkVersion = 15 ), puoi utilizzare le API nascoste aggiungendo alcune classi tuo target android.jar.

Una volta che lo fai, puoi usare provare-con-risorse su qualsiasi Chiudibile, così come implementare Chiudibile automaticamente nelle tue classi.

Ho creato un file zip contenente sorgenti e file binari di tutte le classi che dovevano essere modificate in android.jar per rendere disponibili queste API. Devi solo decomprimerlo e aggiungere i file binari al tuo
android-sdk / platform / android-NN / android.jar

Puoi scaricarlo da qui: http://db.tt/kLxAYWbr

Degna di nota è che, negli ultimi due mesi, Elliott Hughes ha fatto un paio di commit all'albero Android: finiti fuori AutoCloseable , ha aggiunto SafeVarargs , non nascosti varie API , il costruttore fissa di Throwable protetto e aggiunto il supporto per la versione 51 file di classe a dx . Quindi, ci sono finalmente dei progressi in corso.

Modifica (aprile 2014):

Con il rilascio di SDK 19 non è più necessario patchare android.jar con le API aggiuntive.

Il metodo migliore per utilizzare le risorse di prova in Android Studio per un'app destinata a 4.0.3 e versioni successive ( minSdkVersion = 15 ) è aggiungere quanto segue compileOptionsa 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 si lamenterà che non è possibile utilizzare le risorse di prova con questo livello API, ma la mia esperienza è che può farlo. Il progetto verrà creato ed eseguito senza problemi sui dispositivi con 4.0.3 e versioni successive. Non ho avuto problemi con questo, con un'app che è stata installata in dispositivi da 500k +.

Errore di Android Studio

Per ignorare questo avviso, aggiungi quanto segue a lint.xml:

<issue id="NewApi">
    <ignore regexp="Try-with-resources requires API level 19"/>
</issue>

1
Trovo interessante che l'avvertimento del codice di Android Studio affermi che provare-con-risorse è una novità di API 13 e dovrei usarlo. Sebbene non abbia il tempo di testare effettivamente se funziona correttamente.
Daniel Ryan,

1

Sembra che farlo funzionare con la formica pura sia un po 'un problema.

Ma ha funzionato per me: http://www.informit.com/articles/article.aspx?p=1966024


1
L'ho cercato a lungo. Per eliminare i problemi delle persone filtrando l'articolo, dovrai cambiare la riga `<nome proprietà =" java.source "=" 1.5 "/>` nel file build.xml fornito da Android (non quello in il tuo progetto!). Per me era in /opt/android-sdk-update-manager/tools/ant/build.xml
Mateusz Kowalczyk il

No non lo fai. Puoi sovrascrivere quelle proprietà con custom_rules.xml, vedi la mia risposta qui: stackoverflow.com/a/24608415/194894
Flow

1

Per utilizzare le funzionalità Java 7 nella compilazione del codice dal sistema di compilazione basato su formica di Android, inserisci semplicemente quanto segue nel tuo custom_rules.xml directory principale dei tuoi progetti:

custom_rules.xml:

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

0

Alcune persone potrebbero essere interessate a questo progetto git che ho trovato, che sembra consentire di eseguire Java 7 su Android. https://github.com/yareally/Java7-on-Android

Comunque troppo rischio se lo aggiungo al progetto attuale su cui lavoro. Quindi aspetterò fino a quando Google non supporterà ufficialmente Java 7.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.