web-dev-qa-db-fra.com

Java 7 fonctionnalités de langage avec Android

Je me demandais si quelqu'un avait essayé d'utiliser les nouvelles Java 7 fonctionnalités du langage avec Android? Je sais que Android lit le bytecode qui Java = crache et tourne en dex. Donc, je suppose que ma question est la suivante: peut-il comprendre le bytecode de Java 7?

188
Daniel Ryan

Si vous utilisez Android Studio , le Java 7 langue doit être activé automatiquement, sans aucun correctif. Try-with-resource nécessite une API de niveau 19+, ainsi que des éléments de NIO 2.0 manquants.

Si vous ne pouvez pas utiliser les fonctionnalités Java 7, consultez la réponse de @ Nuno == sur la façon de modifier votre build.gradle.

Ce qui suit est pour intérêt historique seulement.


Une petite partie de Java 7 peut certainement être utilisée avec Android (note: je n’ai testé que sur la version 4.1).

Tout d’abord, vous ne pouvez pas utiliser l’ADT d’Eclipse car , il est codé en dur que seuls les compilateurs 1.5 et 1.6 de Java sont compatibles. Vous pouvez recompiler ADT mais je trouve qu’il n’ya pas de moyen simple de le faire en dehors de la recompilation de l’ensemble Android ensemble.

Mais vous n'avez pas besoin d'utiliser Eclipse. Par exemple, Android Studio 0.3.2 , IntelliJ IDEA CE et autres IDE basés sur javac prenant en charge la compilation vers Android et vous pouvez définir la conformité jusqu'à Java 8 avec:

  • Fichier → Structure du projet → Modules → (choisissez le module dans le deuxième volet) → Niveau de langue → (choisissez "7.0 - Diamonds, ARM, multi-captures, etc.")

Enabling Java 7 on IntelliJ

Ceci n'autorise que Java 7 fonctionnalités du langage , et vous ne pouvez guère en tirer profit, car une moitié d'amélioration provient également de la bibliothèque. Les fonctionnalités que vous pouvez utiliser sont celles qui ne dépendent pas de la bibliothèque:

  • Opérateur Diamond (<>)
  • Commutateur de chaîne
  • Attrape multiple (catch (Exc1 | Exc2 e))
  • Souligner les littéraux numériques (1_234_567)
  • Littéraux binaires (0b1110111)

Et ces fonctionnalités ne peuvent pas être utilisées encore:

  • L'instruction try- with-resources - car elle nécessite l'interface non existante "Java.lang.AutoCloseable" (elle peut être utilisée publiquement dans la version 4.4+).
  • L'annotation @SafeVarargs - car "Java.lang.SafeVarargs" n'existe pas

... "encore" :) Il s'avère que, bien que la bibliothèque d'Android vise 1.6, la source Android contient des interfaces du type AutoCloseable et des interfaces traditionnelles. like Closeable hérite d'AutoCloseable (SafeVarargs est toutefois réellement manquant). Nous pourrions confirmer son existence par la réflexion. Ils sont cachés simplement parce que la Javadoc a la balise @hide, Ce qui a empêché le "Android.jar" de les inclure.

La question existe déjà Comment compiler le SDK Android avec des API cachées et internes disponibles? sur la façon de récupérer ces méthodes. Il vous suffit de remplacer la référence "Android.jar" existante de la plate-forme actuelle par la nôtre personnalisée, puis de nombreuses API Java 7 seront disponibles (la procédure est similaire Eclipse (voir Structure du projet → SDK).

En plus d’AutoCloseable, (uniquement) les caractéristiques de bibliothèque Java 7 suivantes sont également révélées:

  • Exception chaînant des constructeurs dans ConcurrentModificationException, LinkageError et AssertionError
  • Les méthodes statiques .compare () pour les primitives: Boolean.compare (), Byte.compare (), Short.compare (), Character.compare (), Integer.compare (), Long.compare ().
  • Currency : .getAvailableCurrency (), .getDisplayName () (mais sans .getNumericCode ())
  • BitSet : .previousSetBit (), .previousClearBit (), .valueOf (), .toLongArray (), .toByteArray ()
  • Collections : .emptyEnumeration (), .emptyIterator (), .emptyListIterator ()
  • AutoCloseable
  • Throwable : .addSuppressed (), .getSuppressed () et le constructeur à 4 arguments
  • Character : .compare (), .isSurrogate (), .getName (), .highSurrogate (), .lowSurrogate (), .isBmpCodePoint () (mais sans .isAlphabetic () et .isIdeographic ())
  • Système: .lineSeparator () (non documenté?)
  • Java.lang.reflect.Modifier : .classModifiers (), .constructorModifiers (), .fieldModifiers (), .interfaceModifiers (), .methodModifiers ()
  • NetworkInterface : .getIndex (), .getByIndex ()
  • InetSocketAddress : .getHostString ()
  • InetAddress : .getLoopbackAddress ()
  • Logger : .getGlobal ()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer : .hasQueuedPredecessors ()
  • DeflaterOutputStream : les 3 constructeurs avec "syncFlush".
  • Deflater : .NO_FLUSH, .SYNC_FLUSH, .FULL_FLUSH, .deflate () avec 4 arguments

C'est fondamentalement tout. En particulier, NIO 2.0 n'existe pas et Arrays.asList n'est toujours pas @SafeVarargs.

164
kennytm

EDIT: Au moment de la rédaction, la dernière version était Android 9 et Eclipse Indigo. Les choses ont changé depuis.

  • Réponse pratique

Oui j'ai essayé. Mais ce n’est pas un bon test car la compatibilité était limitée au niveau 6 sans aucun moyen (vraiment simple du moins) d’utiliser réellement Java 7:

  • J'ai d'abord installé un JDK7 sur une machine sur laquelle aucun autre JDK n'était installé - Eclipse et Android ne sont pas installés non plus:

The 7 is the only installed on this machine

  • Ensuite, j'ai installé une toute nouvelle Eclipse Indigo et vérifié qu'elle utilisait bien le JDK 7 (enfin, comme c'est le seul et c'est celui que j'ai sélectionné, j'aurais été surpris).

The 7 is the only used by this Eclipse

  • Ensuite, j'ai installé la dernière version du Android SDK (EDIT: Honeycomb, API13, au moment de la rédaction de ce message). Il a trouvé mon JDK 7 et l'a installé correctement. Il en va de même pour ADT.

  • Mais j’ai eu une surprise en essayant de compiler et d’exécuter un Hello Word Android app. La compatibilité a été définie sur Java 6 sans aucun moyen de le forcer à = Java 7:

Compatibility is limited to Java 6

  • J'ai essayé avec un projet non-Android, un Java normal), et j'avais l'explication. Le niveau de compatibilité semble être limité par Eclipse (voir le message au bas de l'image suivante):

Eclipse limits itself to level 6 compatibility

Donc, j'avais Hello World, ainsi que d'autres applications plus compliquées et utilisant SQLite, Listview, Sensor et Camera _, mais cela prouve seulement que le traitement de la compatibilité de Java 7 semble être bien fait et fonctionne avec Android.

Alors, est-ce que quelqu'un a essayé avec la bonne vieille Ant de contourner la limitation Eclipse vue ci-dessus?

  • Réponse théroétique

Quoi qu'il en soit, le SDK est conçu pour être utilisé avec Java 5 ou 6, comme expliqué ici .

Il se peut que quelque chose fonctionne avec Java 7, mais cela fonctionnerait "par accident". La construction du DEX peut fonctionner correctement ou non, et une fois que ce dernier est construit, cela peut fonctionner ou non. Ceci parce que l’utilisation d’un JDK non qualifié donne des résultats imprévisibles par définition.

Même si quelqu'un a construit avec succès une Android application sous plain Java 7, cela ne qualifie pas le JDK. Le même processus appliqué à une autre application peut échouer, ou L’application résultante peut contenir des bogues liés à l’utilisation de ce kit JDK.

Pour ceux qui sont impliqués dans le développement d'applications web, cela revient exactement au même que déployer une application Web construite sous Java 5 ou 6 sous un serveur d'applications qualifié pour Java 4 Weblogic 8 par exemple). Cela peut fonctionner, mais ce n’est pas quelque chose qui peut être recommandé à d’autres fins que d’essayer.

70
Shlublu

Citation de dalvikvm.com:

dx, inclus dans le Android SDK, transforme le Java Fichiers de classe de Java classes compilées par un ordinateur ordinaire Java dans un autre format de fichier de classe (le format .dex)

Cela signifie que le fichier source .Java n'a pas d'importance, c'est uniquement le bytecode .class.

Pour autant que je sache, seulement invokedynamic a été ajouté au sous-code de la machine virtuelle Java dans Java 7, le reste est compatible avec Java 6. Le langage Java lui-même Ne pas utiliser invokedynamic. Autres nouvelles fonctionnalités, comme le commutateur déclaration utilisant Chaînes ou le multi-capture ne sont que du sucre syntatique et ne nécessitaient pas de modifications du code octet. Par exemple, le multi-capture il suffit de copier le capture-block pour chaque exception possible.

Le seul problème devrait être que les nouvelles classes introduites dans Java 7 sont manquantes dans Android, comme AutoCloseable, donc je ne suis pas sûr si vous pouvez utiliser le essayerFonction -with-resources (quelqu'un a essayé?).

Des commentaires à ce sujet? Est-ce que je manque quelque chose?

38
Andi

En tant que Android SDK v15, avec Eclipse 3.7.1, Java 7 est ) n'est pas pris en charge pour Android. Définir la compatibilité de la source sur 1.7 impose de définir la compatibilité du fichier .class générée sur 1.7, ce qui entraîne l'erreur suivante de la Android compilateur:

Android requiert le niveau de conformité du compilateur 5.0 ou 6.0. Trouvé '1.7' à la place. Veuillez utiliser Android Outils> Réparer les propriétés du projet.

12
Hosam Aly

Pour développer la réponse ci-dessus de @KennyTM, si vous ciblez les versions 4.0.3 et supérieures ( minSdkVersion = 15 ), vous pouvez utiliser les API masquées de ajouter quelques classes au SDK Android.jar de votre cible.

Une fois cette opération effectuée, vous pouvez utiliser des ressources d’essai avec toutes les machines Closeable, ainsi que mettre en œuvre AutoCloseable dans vos propres classes.

J'ai créé un fichier Zip contenant les sources et les fichiers binaires de toutes les classes devant être modifiées dans Android.jar pour rendre ces API disponibles. Il vous suffit de le décompresser et d’ajouter les fichiers binaires à votre
Android-sdk/plateformes/Android-NN/Android.jar

Vous pouvez le télécharger ici: http://db.tt/kLxAYWbr

Il est également à noter que, au cours des deux derniers mois, Elliott Hughes a effectué quelques validations sur l’arborescence Android tree: fin de la suppression automatique , ajouté SafeVarargs , diverses API non masquées , constructeur protégé de Throwable fixe et ajout du support pour les fichiers de classe version 51 dans dx . des progrès sont en cours.

Modifier (avril 2014):

Avec la sortie du SDK 19, il n'est plus nécessaire de patcher Android.jar avec les API supplémentaires.

La meilleure méthode pour utiliser try-with-resources dans Android Studio pour une application qui cible 4.0.3 et versions ultérieures ( minSdkVersion = 15 ) est la suivante compileOptions à votre 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 se plaindra que les ressources d’essai avec ressources ne peuvent pas être utilisées avec ce niveau d’API, mais je sais par expérience que c’est le cas. Le projet sera construit et exécuté sans problème sur les périphériques 4.0.3 et supérieurs. Je n'ai rencontré aucun problème avec cela, avec une application installée dans plus de 500 000 appareils.

Android Studio error

Pour ignorer cet avertissement, ajoutez ce qui suit à votre lint.xml:

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

Il semble que faire fonctionner cela avec pure fourmi est un peu complaisant.

Mais cela a fonctionné pour moi: http://www.informit.com/articles/article.aspx?p=1966024

1
mako

Pour utiliser Java 7 fonctionnalités dans le code créé par le système de construction basé sur Android, entrez simplement ce qui suit dans votre custom_rules.xml dans le répertoire racine de vos projets:

custom_rules.xml:

<project name="custom_Android_rules">
    <property name="Java.target" value="1.7" />
    <property name="Java.source" value="1.7" />
</project>
1
Flow

Certaines personnes pourraient être intéressées par ce projet git que j'ai trouvé et qui semble permettre d'exécuter Java 7 sur Android. https://github.com/yareally/Java7- sur Android

Cependant, trop de risques si j'ajoute cela dans le projet actuel sur lequel je travaille. Je vais donc attendre que Google prenne officiellement en charge Java 7.

0
Daniel Ryan