Zastanawiasz się, czy ktoś próbował użyć nowych funkcji języka Java 7 w systemie Android? Wiem, że Android odczytuje kod bajtowy wypluwany przez Javę i zmienia go w dex. Wydaje mi się, że moje pytanie brzmi: czy można zrozumieć kod bajtowy Java 7?
Zastanawiasz się, czy ktoś próbował użyć nowych funkcji języka Java 7 w systemie Android? Wiem, że Android odczytuje kod bajtowy wypluwany przez Javę i zmienia go w dex. Wydaje mi się, że moje pytanie brzmi: czy można zrozumieć kod bajtowy Java 7?
Odpowiedzi:
Jeśli używasz Androida Studio , język Java 7 powinien zostać włączony automatycznie bez żadnych łatek. Try-with-resource wymaga interfejsu API na poziomie 19+ i brakuje NIO 2.0.
Jeśli nie możesz korzystać z funkcji Java 7, zobacz odpowiedź @Nuno na temat edytowania build.gradle
.
Poniższe informacje dotyczą wyłącznie historii.
Niewielką część Java 7 można z pewnością używać w Androidzie (uwaga: testowałem tylko na 4.1).
Po pierwsze, nie można było użyć narzędzia ADT Eclipse, ponieważ jest na stałe zakodowane, że tylko kompilator Java 1.5 i 1.6 jest zgodny. Możesz przekompilować ADT, ale uważam, że nie ma prostego sposobu na zrobienie tego oprócz ponownej kompilacji całego Androida.
Ale nie musisz używać Eclipse. Na przykład Android Studio 0.3.2 , IntelliJ IDEA CE i inne IDE oparte na Javie obsługują kompilację do Androida, a zgodność można ustawić nawet do Java 8 za pomocą:
Pozwala to tylko na funkcje języka Java 7 i nie można z niczego skorzystać, ponieważ połowa ulepszeń pochodzi również z biblioteki. Można użyć funkcji, które nie zależą od biblioteki:
<>
)catch (Exc1 | Exc2 e)
)1_234_567
)0b1110111
)Z tych funkcji nie można jeszcze korzystać :
try
-with-resources - ponieważ wymaga nieistniejącego interfejsu „java.lang.AutoCloseable” (można tego użyć publicznie w wersji 4.4+)... „jeszcze” :) Okazuje się, że chociaż biblioteka Androida jest ukierunkowana na wersję 1.6, źródło Androida zawiera interfejsy takie jak AutoCloseable, a tradycyjne interfejsy takie jak Closeable dziedziczą po AutoCloseable (choć SafeVarargs naprawdę brakuje). Możemy potwierdzić jego istnienie poprzez refleksję. Są one ukryte po prostu dlatego, że Javadoc ma @hide
znacznik, co spowodowało, że plik „android.jar” ich nie zawiera.
Istnieje już istniejące pytanie Jak zbudować zestaw Android SDK z dostępnymi ukrytymi i wewnętrznymi interfejsami API? jak odzyskać te metody. Wystarczy zastąpić istniejące odwołanie „android.jar” bieżącej platformy naszym dostosowanym, a następnie dostępnych będzie wiele interfejsów API Java 7 (procedura jest podobna do tej w Eclipse. Sprawdź Strukturę Projektu → SDK.)
Oprócz AutoCloseable ujawniono (tylko) następujące funkcje biblioteki Java 7 :
To w zasadzie wszystko. W szczególności NIO 2.0 nie istnieje, a Arrays.asList nadal nie jest @SafeVarargs.
nio2
a inne gadżety z pewnością będą dobrą wiadomością.
AutoCloseable
interfejs nie istnieje w środowisku uruchomieniowym Androida do czasu ICS (a może do HoneyComb). Więc nawet jeśli użyjesz załatanego pliku android.jar, otrzymasz go NoClassDefFoundError
w systemie 2.x.
invokedynamic
która nie jest obsługiwana przez JVM atakujący Javę 6.
EDYCJA: W chwili pisania tego tekstu najnowszą wersją był Android 9 i Eclipse Indigo. Od tego czasu coś się zmieniło.
Tak, próbowałem. Ale to nie jest świetny test, ponieważ zgodność była ograniczona do poziomu 6 bez żadnego sposobu (przynajmniej nie ma prostego sposobu), aby naprawdę korzystać z java 7:
Następnie zainstalowałem najnowszą wersję zestawu Android SDK (EDIT: Honeycomb, API13, w momencie pisania tego postu). Znaleziono mój JDK 7 i został poprawnie zainstalowany. To samo dotyczy ADT.
Ale miałem niespodziankę, próbując skompilować i uruchomić aplikację Hello Word na Androida. Kompatybilność została ustawiona na Javę 6 bez możliwości wymuszenia jej na Javie 7:
Więc musiałem Hello World pracy, a także inne aplikacje, bardziej skomplikowane i za pomocą SQLite
, Listview
, Sensor
i Camera
, ale to tylko dowodzi, że obsługa Java 7 zgodności wydaje się być dobrze zrobione i działa z systemem Android.
Czy ktoś próbował ze starą dobrą mrówką ominąć ograniczenie Eclipse widoczne powyżej?
W każdym razie SDK jest zaprojektowany do pracy z Javą 5 lub 6, jak wyjaśniono tutaj .
Możemy mieć coś do pracy z Javą 7, ale działałoby to „przez przypadek”. Budowanie DEX może działać poprawnie lub nie, a po zbudowaniu DEX może działać lub nie. Jest tak, ponieważ użycie niekwalifikowanego pakietu JDK z definicji daje nieprzewidywalne wyniki.
Nawet jeśli ktoś z powodzeniem zbudował aplikację na Androida na zwykłym Javie 7, nie kwalifikuje się do JDK. Ten sam proces zastosowany do innej aplikacji może się nie powieść lub aplikacja wynikowa może zawierać błędy związane z korzystaniem z tego JDK. Niepolecane.
Dla tych, którzy są zaangażowani w tworzenie aplikacji internetowych, jest to dokładnie to samo, co wdrażanie aplikacji WWW zbudowanej pod Javą 5 lub 6 na serwerze aplikacji kwalifikującym się tylko do Java 4 (powiedzmy na przykład Weblogic 8). Może to działać, ale nie jest to coś, co można polecić do innych celów niż próba.
Cytat z dalvikvm.com:
dx, zawarte w pakiecie Android SDK, przekształca pliki klas Java klas Java skompilowanych przez zwykły kompilator Java w inny format plików klas (format .dex)
Oznacza to, że plik źródłowy .java nie ma znaczenia, to tylko kod bajtowy klasy.
O ile mi wiadomo, do kodu bajtowego JVM w Javie 7 dodano tylko invokedynamic , reszta jest kompatybilna z Javą 6. Sam język Java nie używa invokedynamic . Inne nowe funkcje, takie jak instrukcja switch wykorzystująca String s lub multi- catch, to po prostu cukier syntetyczny i nie wymagały zmian kodu bajtowego. Na przykład, multi- połowowe tylko kopiuje haczyk -blok dla każdej możliwej wyjątku.
Jedynym problemem powinno być to, że w Androidzie brakuje nowych klas wprowadzonych w Javie 7, takich jak AutoCloseable , więc nie jestem pewien, czy możesz użyć funkcji try -with-resources (ktoś próbował?).
Jakieś komentarze na ten temat? Czy coś brakuje?
Począwszy od zestawu Android SDK v15, wraz z Eclipse 3.7.1, Java 7 nie jest obsługiwana w programowaniu Androida. Ustawienie zgodności źródła na 1.7 wymaga ustawienia wygenerowanej zgodności pliku .class na 1.7, co prowadzi do następującego błędu kompilatora Androida:
Android wymaga zgodności kompilatora na poziomie 5.0 lub 6.0. Zamiast tego znaleziono „1.7”. Proszę użyć Narzędzia Android> Napraw właściwości projektu.
Aby rozwinąć powyższą odpowiedź przez @KennyTM, jeśli kierujesz reklamy na wersję 4.0.3 i nowszą ( minSdkVersion = 15 ), możesz użyć ukrytych interfejsów API, dodając kilka klas do zestawu SDK celu.jpg.
Gdy to zrobisz, możesz użyć try-with-resources na dowolnym Closeable, a także zaimplementować AutoCloseable we własnych klasach.
Zrobiłem zip zawierający źródła i pliki binarne wszystkich klas, które musiały zostać zmodyfikowane w android.jar, aby te API były dostępne. Wystarczy go rozpakować i dodać pliki binarne do
Androida-SDK / Platform / Android-NN / Android.jar
Możesz go pobrać stąd: http://db.tt/kLxAYWbr
Warto również zauważyć, że w ciągu ostatnich kilku miesięcy Elliott Hughes dokonał kilku zmian w drzewie Androida: zakończył AutoCloseable , dodał SafeVarargs , niejawne różne API , naprawił chroniony konstruktor Throwable i dodał obsługę plików klasy 51 w dx . Tak więc wreszcie nastąpił pewien postęp.
Edycja (kwiecień 2014):
Wraz z wydaniem zestawu SDK 19 nie jest już konieczne łatanie pliku android.jar za pomocą dodatkowych interfejsów API.
Najlepszą metodą użycia try-with-resources w Android Studio dla aplikacji, która jest kierowana do wersji 4.0.3 i nowszych ( minSdkVersion = 15 ), jest dodanie compileOptions
do 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 będzie narzekać, że z tym poziomem interfejsu API nie można używać opcji wypróbowania zasobów, ale z mojego doświadczenia wynika, że może. Projekt zostanie zbudowany i uruchomiony bez problemów na urządzeniach z wersją 4.0.3 i nowszą. Nie spotkałem się z tym z żadnymi problemami z aplikacją zainstalowaną na urządzeniach 500k +.
Aby zignorować to ostrzeżenie, dodaj następujące elementy do lint.xml
:
<issue id="NewApi">
<ignore regexp="Try-with-resources requires API level 19"/>
</issue>
Wygląda na to, że uruchomienie tego z czystą mrówką jest trochę kłopotliwe.
Ale zadziałało to dla mnie: http://www.informit.com/articles/article.aspx?p=1966024
custom_rules.xml
, patrz moja odpowiedź tutaj: stackoverflow.com/a/24608415/194894
Aby korzystać z funkcji Java 7 w kompilacji kodu przez system kompilacji oparty na mrówkach Androida, po prostu umieść w custom_rules.xml
katalogu głównym projektów:
custom_rules.xml:
<project name="custom_android_rules">
<property name="java.target" value="1.7" />
<property name="java.source" value="1.7" />
</project>
Niektórzy ludzie mogą być zainteresowani tym projektem git, który znalazłem, który pozwala na uruchomienie Java 7 na Androidzie. https://github.com/yareally/Java7-on-Android
Jednak zbyt duże ryzyko, jeśli dodam to w bieżącym projekcie, nad którym pracuję. Zaczekam więc, aż Google oficjalnie wesprze Javę 7.