Java 7 Sprachfunktionen mit Android

188

Sie fragen sich nur, ob jemand versucht hat, neue Java 7-Sprachfunktionen mit Android zu verwenden? Ich weiß, dass Android den Bytecode liest, den Java ausspuckt, und ihn in Dex umwandelt. Meine Frage ist also, ob es den Bytecode von Java 7 verstehen kann.

Daniel Ryan
quelle
10
Alternativ können Sie möglicherweise die Java 7-Sprachfunktionen verwenden, aber mit Java 6-Bytecode kompilieren?
MatrixFrog
2
Android Studio gibt Ihnen jetzt eine Benachrichtigung, wenn Sie ein neues Projekt erstellen: "Mit minSdkVersion unter 19 können Sie Try-with-Resources nicht verwenden, aber andere Java 7-
Sprachfunktionen
1
Ja, ich weiß :) Wir verwenden endlich Java 7 in unserem Projekt.
Daniel Ryan

Antworten:

165

Wenn Sie Android Studio verwenden , die Java 7- Sprache automatisch ohne Patches aktiviert werden. Für das Ausprobieren von Ressourcen ist API Level 19+ erforderlich, und NIO 2.0-Inhalte fehlen.

Wenn Sie keine Java 7-Funktionen verwenden können, lesen Sie die Antwort von @Nuno zum Bearbeiten Ihrer build.gradle.

Das Folgende ist nur für historisches Interesse.


Ein kleiner Teil von Java 7 kann sicherlich mit Android verwendet werden (Hinweis: Ich habe nur auf 4.1 getestet).

Erstens konnten Sie Eclipse's ADT nicht verwenden, da fest codiert ist, dass nur Java Compiler 1.5 und 1.6 kompatibel sind. Sie könnten ADT neu kompilieren, aber ich finde, es gibt keinen einfachen Weg, dies zu tun, außer das gesamte Android zusammen neu zu kompilieren.

Sie müssen Eclipse jedoch nicht verwenden. Zum Beispiel unterstützen Android Studio 0.3.2 , IntelliJ IDEA CE und andere Javac-basierte IDEs das Kompilieren auf Android, und Sie können die Konformität sogar auf Java 8 einstellen mit:

  • Datei → Projektstruktur → Module → (wählen Sie das Modul im 2. Bereich aus) → Sprachstufe → (wählen Sie "7.0 - Diamanten, ARM, Multi-Catch usw.")

Aktivieren von Java 7 unter IntelliJ

Dies erlaubt nur Java 7- Sprachfunktionen , und Sie können kaum von irgendetwas profitieren, da eine halbe Verbesserung auch von der Bibliothek kommt. Funktionen, die Sie verwenden können, sind diejenigen, die nicht von der Bibliothek abhängen:

  • Diamantoperator ( <>)
  • String-Schalter
  • Mehrfachfang ( catch (Exc1 | Exc2 e))
  • Unterstreichen Sie in Zahlenliteralen ( 1_234_567)
  • Binäre Literale ( 0b1110111)

Und diese Funktionen können noch nicht verwendet werden :

  • Die tryAnweisung -with-resources - da die nicht vorhandene Schnittstelle "java.lang.AutoCloseable" erforderlich ist (diese kann in 4.4+ öffentlich verwendet werden).
  • Die Annotation @SafeVarargs - da "java.lang.SafeVarargs" nicht vorhanden ist

... "noch" :) Es stellt sich heraus, dass die Android-Quelle, obwohl die Bibliothek von Android auf 1.6 abzielt, Schnittstellen wie AutoCloseable enthält und herkömmliche Schnittstellen wie Closeable von AutoCloseable erben (SafeVarargs fehlt jedoch wirklich). Wir könnten seine Existenz durch Reflexion bestätigen. Sie werden einfach versteckt, weil der Javadoc das @hideTag hat, was dazu führte, dass die "android.jar" sie nicht enthielt.

Es gibt bereits eine Frage: Wie erstelle ich das Android SDK mit versteckten und internen APIs? wie man diese Methoden zurückbekommt. Sie müssen nur ersetzen die vorhandene "android.jar" -Referenz der aktuellen Plattform durch unsere angepasste , dann werden viele der Java 7-APIs verfügbar (die Vorgehensweise ähnelt der in Eclipse. Überprüfen Sie die Projektstruktur → SDKs.)

Zusätzlich zu AutoCloseable werden (nur) die folgenden Funktionen der Java 7- Bibliothek angezeigt :

  • Konstruktoren für die Verkettung von Ausnahmen in ConcurrentModificationException, LinkageError und AssertionError
  • Die statischen .compare () -Methoden für Grundelemente: Boolean.compare (), Byte.compare (), Short.compare (), Character.compare (), Integer.compare (), Long.compare ().
  • Währung : .getAvailableCurrencies (), .getDisplayName () (jedoch ohne .getNumericCode ())
  • BitSet : .previousSetBit (), .previousClearBit (), .valueOf (), .toLongArray (), .toByteArray ()
  • Sammlungen : .emptyEnumeration (), .emptyIterator (), .emptyListIterator ()
  • AutoCloseable
  • Throwable : .addSuppressed (), .getSuppressed () und der Konstruktor mit 4 Argumenten
  • Zeichen : .compare (), .isSurrogate (), .getName (), .highSurrogate (), .lowSurrogate (), .isBmpCodePoint () (jedoch ohne .isAlphabetic () und .isIdeographic ())
  • System: .lineSeparator () (undokumentiert?)
  • java.lang.reflect.Modifier : .classModifiers (), .constructorModifiers (), .fieldModifiers (), .interfaceModifiers (), .methodModifiers ()
  • Netzwerkschnittstelle : .getIndex (), .getByIndex ()
  • InetSocketAddress : .getHostString ()
  • InetAddress : .getLoopbackAddress ()
  • Logger : .getGlobal ()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer : .hasQueuedPredecessors ()
  • DeflaterOutputStream : Die 3 Konstruktoren mit "syncFlush".
  • Deflater : .NO_FLUSH, .SYNC_FLUSH, .FULL_FLUSH, .deflate () mit 4 Argumenten

Das ist im Grunde alles. Insbesondere existiert NIO 2.0 nicht und Arrays.asList ist immer noch nicht @SafeVarargs.

kennytm
quelle
2
Gute Antwort. Ich hoffe, dass bald in Zukunft die volle Unterstützung auf JVM-Ebene erfolgt nio2und andere Goodies definitiv eine gute Nachricht sind.
SD
4
Erwähnenswert ist, dass die AutoCloseableBenutzeroberfläche in der Android-Laufzeit erst mit ICS (oder vielleicht bis HoneyComb) vorhanden ist. Selbst wenn Sie gepatchte android.jar verwenden, erhalten Sie NoClassDefFoundErrorauf dem 2.x-System.
Idolon
2
@deviant: Dazu muss die Dalvik-VM geändert werden, da Java 8 Lambda verwendet, invokedynamicwas von der JVM für Java 6 nicht unterstützt wird.
kennytm
2
Möglicherweise möchten Sie ein Update hinzufügen, das ab Android Studio 3.2 vollständig unterstützt wird, ebenso wie das
Testen
4
Versuch mit Ressourcen kann jetzt auf SDK 19 (Android Kitkat) verwendet werden. siehe tools.android.com/recent/androidstudio032released
Mohamed El-Nakib
70

EDIT: Zu der Zeit, als dies geschrieben wurde, war die neueste Version Android 9 und Eclipse Indigo. Die Dinge haben sich seitdem geändert.

  • Praktische Antwort

Ja, ich habe es versucht. Dies ist jedoch kein großartiger Test, da die Kompatibilität auf Level 6 beschränkt war und es keine Möglichkeit gab (zumindest keine einfache), Java 7 wirklich zu verwenden:

  • Zuerst habe ich ein JDK7 auf einem Computer installiert, auf dem kein anderes JDK installiert war. Eclipse und Android sind ebenfalls nicht installiert:

Die 7 ist die einzige auf diesem Computer installierte

  • Dann habe ich einen brandneuen Eclipse Indigo installiert und überprüft, ob er tatsächlich das JDK 7 verwendet (nun, da dies der einzige ist und ich diesen ausgewählt habe, wäre ich überrascht gewesen).

Die 7 wird nur von dieser Eclipse verwendet

  • Dann habe ich die neueste Version des Android SDK installiert (BEARBEITEN: Honeycomb, API13, als dieser Beitrag geschrieben wurde). Es hat mein JDK 7 gefunden und ordnungsgemäß installiert. Gleiches gilt für ADT.

  • Aber ich hatte eine Überraschung, als ich versuchte, eine Hello Word Android-App zu kompilieren und auszuführen. Die Kompatibilität wurde auf Java 6 eingestellt, ohne dass dies auf Java 7 erzwungen werden konnte:

Die Kompatibilität ist auf Java 6 beschränkt

  • Ich habe es mit einem Nicht-Android-Projekt versucht, einem normalen Java-Projekt, und ich hatte die Erklärung. Die Kompatibilitätsstufe scheint durch Eclipse begrenzt zu sein (siehe die Meldung unten im folgenden Bild):

Eclipse beschränkt sich auf Level 6-Kompatibilität

Also hatte ich Hello World und auch andere Apps, die komplizierter und benutzerfreundlicher SQLitewaren Listview, SensorundCamera , aber dies beweist nur, dass die Kompatibilitätsbehandlung von Java 7 gut gemacht zu sein scheint und mit Android funktioniert.

Hat jemand mit der guten alten Ameise versucht, die oben gezeigte Eclipse-Einschränkung zu umgehen?

  • Theroetische Antwort

Wie hier erläutert, ist das SDK für die Verwendung mit Java 5 oder 6 ausgelegt .

Möglicherweise funktioniert etwas mit Java 7, aber es würde "aus Versehen" funktionieren. Das Erstellen des DEX funktioniert möglicherweise ordnungsgemäß oder nicht, und sobald das DEX erstellt wurde, funktioniert es möglicherweise oder nicht. Dies liegt daran, dass die Verwendung eines nicht qualifizierten JDK per Definition unvorhersehbare Ergebnisse liefert.

Selbst wenn jemand erfolgreich eine Android-App unter einfachem Java 7 erstellt hat, qualifiziert dies das JDK nicht. Der gleiche Prozess, der auf eine andere Anwendung angewendet wird, schlägt möglicherweise fehl, oder die resultierende Anwendung weist möglicherweise Fehler auf, die mit der Verwendung dieses JDK zusammenhängen. Nicht empfohlen.

Für diejenigen, die an der Entwicklung von Webanwendungen beteiligt sind, entspricht dies genau der Bereitstellung einer unter Java 5 oder 6 erstellten Webanwendung unter einem nur für Java 4 qualifizierten Anwendungsserver (z. B. Weblogic 8). Dies mag funktionieren, kann jedoch nicht für andere Zwecke als zum Ausprobieren empfohlen werden.

Shlublu
quelle
1
Vielen Dank für die ausführliche Bewertung. Es sieht also so aus, als könnten Sie keine Java 7-Sprachfunktionen verwenden, aber dennoch Java 7 als Java 6 verwenden. Hoffentlich ändert sich dies bald :)
Daniel Ryan
Dies ist mit Eclipse. Mit Ant ist dies wahrscheinlich möglich. Ich hoffe, jemand wird den Test machen und ich beschuldige mich, zu faul zu sein, um es zu tun :)
Shlublu
Ja, Varga, aber ich glaube nicht, dass die Compiler-Versionsbeschränkung von Ant stammt, sondern von Eclipse.
Shlublu
2
Beachten Sie auch, dass die bereitgestellten Tools nicht kompatibel sind, wenn Sie mit mehreren Java-Versionen spielen. Ich meine, wenn Sie Ihre App zuerst mit Jarsigner von Java 6 Tools signiert und später Java 7 installiert und eine neue Version unserer App mit dem Jarsigner signiert haben, der mit Java 7 und demselben Keystore wie zuvor geliefert wurde, stimmen die Signaturen nicht überein !
Timo
38

Zitat von dalvikvm.com:

dx, das im Android SDK enthalten ist, transformiert die Java-Klassendateien von Java-Klassen, die von einem regulären Java-Compiler kompiliert wurden, in ein anderes Klassendateiformat (das .dex-Format).

Das heißt, die .java-Quelldatei spielt keine Rolle, es ist nur der .class-Bytecode.

Soweit ich weiß, wurde dem Java-Bytecode in Java 7 nur invokedynamic hinzugefügt, der Rest ist mit Java 6 kompatibel. Die Java-Sprache selbst verwendet invokedynamic nicht . Andere neue Funktionen, wie die switch- Anweisung mit String s oder der Multi- catch, sind nur syntatischer Zucker und erforderten keine Änderungen des Bytecodes. Beispielsweise kopiert der Multi- Catch nur den Catch- Block für jede mögliche Ausnahme.

Das einzige Problem sollte sein, dass die in Java 7 eingeführten neuen Klassen in Android wie AutoCloseable fehlen. Ich bin mir also nicht sicher, ob Sie die Funktion "Mit Ressourcen versuchen" verwenden können (jemand hat es versucht?).

Irgendwelche Kommentare dazu? Vermisse ich etwas

Und ich
quelle
2
Das Problem ist nun, wie wir konfigurieren, dass Java 7-Quellcodes in Java 6-Klassendateien kompiliert werden, insbesondere in Eclipse.
Randy Sugianto 'Yuku'
Die Frage bleibt nur, warum Sie sich überhaupt die Mühe machen würden.
Warpzit
@ Warpzit die größere Frage sollte sein, warum ein Entwickler sich nicht um all diese Verwirrung
Amit
@Amit, weil er erkannt hat, dass Android anders ist als Java, und um mit Android arbeiten zu können, muss er die angebotenen Tools verwenden.
Warpzit
2
@ Warpzit Seine einzige Frage ist " Kann Android Java 7 verstehen? " Ignoranz ist nie eine Lösung / Antwort ...
Amit
12

Ab dem Android SDK v15 wird Java 7 zusammen mit Eclipse 3.7.1 für die Android-Entwicklung nicht unterstützt. Das Festlegen der Quellkompatibilität auf 1.7 erfordert das Festlegen der generierten .class-Dateikompatibilität auf 1.7, was zu folgendem Fehler des Android-Compilers führt:

Für Android ist die Compiler-Konformitätsstufe 5.0 oder 6.0 erforderlich. Fand stattdessen '1.7'. Bitte verwenden Sie Android Tools> Projekteigenschaften korrigieren.

Hosam Aly
quelle
5

Um die obige Antwort von @KennyTM zu erweitern, wenn Sie auf 4.0.3 und höher abzielen ( minSdkVersion = 15 ), die versteckten APIs verwenden, indem Sie dem SDK android.jar Ihres Ziels einige Klassen hinzufügen.

Sobald Sie dies getan haben, können Sie Try-with-Resources für jedes Closeable verwenden und AutoCloseable in Ihren eigenen Klassen implementieren.

Ich habe eine Zip-Datei erstellt, die Quellen und Binärdateien aller Klassen enthält, die in android.jar geändert werden mussten, um diese APIs verfügbar zu machen. Sie müssen es nur entpacken und die Binärdateien zu Ihrem
android-sdk / platform / android-NN / android.jar hinzufügen

Sie können es hier herunterladen: http://db.tt/kLxAYWbr

Auch der Hinweis das heißt, in den letzten paar Monaten hat Elliott Hughes ein paar Commits zum Android Baum gemacht: fertig off AutoCloseable , hinzugefügt SafeVarargs , unhidden verschiedene APIs , feste Throwable geschützten Konstruktor und zusätzliche Unterstützung für Version 51 Klassendateien in dx . Es gibt also endlich einige Fortschritte.

Bearbeiten (April 2014):

Mit der Veröffentlichung von SDK 19 ist es nicht mehr erforderlich, android.jar mit den zusätzlichen APIs zu patchen.

Die beste Methode, um Try-with-Resources in Android Studio für eine App zu verwenden, die auf 4.0.3 und höher abzielt ( minSdkVersion = 15 ), besteht darin, Folgendes compileOptionszu Ihrem Programm hinzuzufügen 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 wird sich beschweren, dass Try-with-Resources mit dieser API-Ebene nicht verwendet werden kann, aber meiner Erfahrung nach ist dies möglich. Das Projekt wird problemlos auf Geräten mit 4.0.3 und höher erstellt und ausgeführt. Ich habe keine Probleme damit gehabt, mit einer App, die auf über 500.000 Geräten installiert wurde.

Android Studio Fehler

Fügen Sie Folgendes hinzu, um diese Warnung zu ignorieren lint.xml:

<issue id="NewApi">
    <ignore regexp="Try-with-resources requires API level 19"/>
</issue>
Nuno Cruces
quelle
1
Ich finde es interessant, dass die Android Studio-Code-Warnung besagt, dass Try-with-Resources in API 13 neu ist und ich es verwenden sollte. Sie haben jedoch keine Zeit, um zu testen, ob es richtig funktioniert.
Daniel Ryan
1

Es scheint, dass es ein bisschen schwierig ist, dies mit reinen Ameisen zum Laufen zu bringen.

Aber es hat bei mir funktioniert: http://www.informit.com/articles/article.aspx?p=1966024

Mako
quelle
1
Ich habe lange danach gesucht. Um Probleme beim Filtern durch den Artikel zu vermeiden, müssen Sie die Zeile `<property name =" java.source "value =" 1.5 "/>` in der build.xml ändern, die von Android bereitgestellt wird (nicht die in dein Projekt!). Für mich war es in /opt/android-sdk-update-manager/tools/ant/build.xml
Mateusz Kowalczyk
Nein, tust du nicht. Sie können diese Eigenschaften überschreiben mit custom_rules.xml, siehe meine Antwort hier: stackoverflow.com/a/24608415/194894
Flow
1

Um Java 7-Funktionen beim Erstellen von Code mit dem ant-basierten Build-System von Android zu verwenden, fügen Sie einfach Folgendes in Ihr custom_rules.xmlStammverzeichnis Ihres Projekts ein:

custom_rules.xml:

<project name="custom_android_rules">
    <property name="java.target" value="1.7" />
    <property name="java.source" value="1.7" />
</project>
Fließen
quelle
0

Einige Leute könnten an diesem Git-Projekt interessiert sein, das ich gefunden habe und das es anscheinend erlaubt, Java 7 auf Android auszuführen. https://github.com/yareally/Java7-on-Android

Allerdings ein zu großes Risiko, wenn ich dies in das aktuelle Projekt einfüge, an dem ich arbeite. Also werde ich warten, bis Google Java 7 offiziell unterstützt.

Daniel Ryan
quelle