Android
Multidex i limit metody Dex
Szukaj…
Wprowadzenie
DEX oznacza pliki wykonywalne kodu bajtowego aplikacji na Androida (APK) w postaci plików wykonywalnych Dalvik (DEX), które zawierają skompilowany kod użyty do uruchomienia aplikacji.
Specyfikacja pliku wykonywalnego Dalvik ogranicza całkowitą liczbę metod, do których można odwoływać się w pojedynczym pliku DEX, do 65 536 (64 KB) - w tym metod frameworku Androida, metod bibliotecznych i metod we własnym kodzie.
Aby pokonać ten limit, należy skonfigurować proces kompilacji aplikacji, aby wygenerować więcej niż jeden plik DEX, znany jako Multidex.
Uwagi
Co to jest dex?
Dex to nazwa formatu pliku i kodowania, do którego skompilowany jest kod Java systemu Android. Wczesne wersje Androida ładowały i wykonywały pliki binarne dex
bezpośrednio na maszynie wirtualnej o nazwie Dalvik. Nowsze wersje Androida używają Android Runtime (ART), który traktuje pliki dex
jako reprezentację pośrednią i wykonuje na nim dalsze kompilacje przed uruchomieniem aplikacji.
Dex jest bardzo starym formatem plików, jeśli chodzi o żywotność smartfonów, i został zaprojektowany dla urządzeń, których główna pamięć została zmierzona w dziesiątkach megabajtów. Ograniczenia projektowe tych dni pozostały z nami do dziś.
Problem:
Format pliku dex
koduje ograniczenie liczby metod, do których można się odwoływać w pojedynczym pliku binarnym. Ponieważ część formatu pliku, w której przechowywana jest liczba odwołań, ma długość dwóch bajtów, maksymalna liczba odwołań do metod wynosi 0xFFFF
lub 65535. Jeśli aplikacja zawiera więcej niż tę liczbę odwołań do metod, kompilacja się nie powiedzie.
Co z tym zrobić:
Google wyjaśnił ten problem pod nazwą Multidex. Ma składniki kompilacji i czasu wykonywania. Jak sama nazwa wskazuje, w czasie kompilacji podzieli kod między jeden lub więcej plików dex
. W czasie wykonywania nauczy domyślnego ClassLoader
jak wyszukiwać klasy z tych plików.
To podejście działa dobrze na nowszych urządzeniach, ale ma pewne istotne wady. Może to znacznie wydłużyć czas uruchamiania aplikacji, a na starszych urządzeniach może powodować awarie Application Not Responding
.
Jeśli to możliwe, należy unikać Multidex, chociaż jest skuteczny.
Jak uniknąć limitu:
Przed skonfigurowaniem aplikacji w celu umożliwienia korzystania z 64 KB lub większej liczby referencji metod należy podjąć kroki w celu zmniejszenia całkowitej liczby referencji wywoływanych przez kod aplikacji, w tym metod zdefiniowanych przez kod aplikacji lub dołączone biblioteki. Następujące strategie mogą pomóc uniknąć przekroczenia limitu odniesienia dex:
- Przejrzyj bezpośrednie i przechodnie zależności aplikacji - upewnij się, że wszelkie duże zależności biblioteki zawarte w aplikacji są używane w sposób, który przewyższa ilość kodu dodawanego do aplikacji. Powszechnym anty-wzorcem jest dołączanie bardzo dużej biblioteki, ponieważ użyteczne było kilka metod narzędziowych. Zmniejszenie zależności kodu aplikacji może często pomóc w uniknięciu limitu odniesienia dex.
- Usuń nieużywany kod za pomocą ProGuard - Skonfiguruj ustawienia ProGuard dla swojej aplikacji, aby uruchomić ProGuard i upewnij się, że masz włączoną funkcję zmniejszania kompilacji wersji. Włączenie zmniejszania gwarantuje, że nie wysyłasz nieużywanego kodu z pakietami APK.
Pierwszy punkt wymaga staranności i dyscypliny ze strony dewelopera. Dołączając biblioteki innych firm, należy wziąć pod uwagę rozmiar biblioteki. Na przykład dwie popularne biblioteki JSON to Jackson i Gson. Funkcjonalnie są dość podobne, ale Gson ma większe zastosowanie w Androidzie. Jednym z powodów jest to, że Jackson waży około 9 000 metod, podczas gdy Gson wnosi 1900.
Dostępnych jest kilka narzędzi ułatwiających programistom śledzenie wielkości ich aplikacji:
- dexcount-gradle-plugin zgłasza liczbę odwołań do metod w twoim APK lub AAR dla każdej kompilacji
- dex-method-counts to narzędzie wiersza polecenia, które zlicza liczbę odwołań do metod w pliku APK
- www.methodscount.com to usługa internetowa, która będzie liczyć odniesienia do metod w każdym przesłanym pliku APK.
Multidex przy użyciu MultiDexApplication bezpośrednio
Użyj tej opcji, jeśli nie potrzebujesz podklasy Application
.
Jest to najprostsza opcja, ale w ten sposób nie można podać własnej podklasy Application
. Jeśli potrzebna jest podklasa Application
, musisz przełączyć się na jedną z innych opcji, aby to zrobić.
W przypadku tej opcji wystarczy podać w pełni kwalifikowaną nazwę klasy android.support.multidex.MultiDexApplication
dla android:name
właściwość tagu application
w pliku AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.multidex.myapplication">
<application
...
android:name="android.support.multidex.MultiDexApplication">
...
</application>
</manifest>
Multidex poprzez rozszerzenie aplikacji
Użyj tej opcji, jeśli twój projekt wymaga podklasy Application
.
Określ tę podklasę Application
używając właściwości android:name
w pliku manifestu wewnątrz tagu application
.
W podklasie Application
dodaj przesłonięcie metody attachBaseContext()
, a w tej metodzie wywołaj MultiDex.install()
:
package com.example;
import android.app.Application;
import android.content.Context;
/**
* Extended application that support multidex
*/
public class MyApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
Upewnij się, że podklasa Application
jest podana w znaczniku application
w pliku AndroidManifest.xml:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>
Włączanie Multidex
Aby włączyć konfigurację multidex, potrzebujesz:
- aby zmienić konfigurację kompilacji Gradle
- aby użyć
MultiDexApplication
lub włączyć MultiDex w swojej klasieApplication
Konfiguracja stopniowa
W app/build.gradle
dodaj te części:
android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
defaultConfig {
...
minSdkVersion 14
targetSdkVersion 24
...
// Enabling multidex support.
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
Włącz MultiDex w swojej aplikacji
Następnie przejdź do jednej z trzech opcji:
Po dodaniu tych ustawień konfiguracji do aplikacji narzędzia do budowania systemu Android konstruują podstawowy plik dex (klasy.dex) i obsługujący go (klas2.dex, klas3.dex) w razie potrzeby.
System kompilacji następnie spakuje je do pliku APK w celu dystrybucji.
Referencje do metod liczenia na każdej kompilacji (wtyczka Dexcount Gradle)
Wtyczka dexcount zlicza metody i zasoby klasy po udanej kompilacji.
Dodaj wtyczkę do app/build.gradle
:
apply plugin: 'com.android.application'
buildscript {
repositories {
mavenCentral() // or jcenter()
}
dependencies {
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.5.5'
}
}
Zastosuj wtyczkę w pliku app/build.gradle
:
apply plugin: 'com.getkeepsafe.dexcount'
Poszukaj danych wyjściowych wygenerowanych przez wtyczkę:
../app/build/outputs/dexcount
Szczególnie przydatny jest wykres .html w:
../app/build/outputs/dexcount/debugChart/index.html
Multidex poprzez rozszerzenie MultiDexApplication
Jest to bardzo podobne do korzystania z podklasy Application
i przesłaniania metody attachBaseContext()
.
Jednak przy użyciu tej metody nie trzeba zastępować attachBaseContext()
ponieważ jest to już zrobione w MultiDexApplication
.
Rozszerz Application
MultiDexApplication
zamiast Application
:
package com.example;
import android.support.multidex.MultiDexApplication;
import android.content.Context;
/**
* Extended MultiDexApplication
*/
public class MyApplication extends MultiDexApplication {
// No need to override attachBaseContext()
//..........
}
Dodaj tę klasę do pliku AndroidManifest.xml dokładnie tak, jakbyś rozszerzał aplikację:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>