Android
Multidex och Dex-metodgränsen
Sök…
Introduktion
DEX betyder Android-appens (APK) körbara bytekodfiler i form av Dalvik Executable (DEX) -filer, som innehåller den sammanställda koden som används för att köra din app.
Den exekverbara Dalvik-specifikationen begränsar det totala antalet metoder som kan hänvisas till i en enda DEX-fil till 65 536 (64K) - inklusive Android-rammetoder, biblioteksmetoder och metoder i din egen kod.
För att övervinna denna gräns krävs att du konfigurerar appen för att generera mer än en DEX-fil, känd som en Multidex.
Anmärkningar
Vad är dex?
Dex är namnet på filformatet och kodningen till vilken Android Java-kod är kompilerad. Tidigare versioner av Android skulle ladda och köra dex
binärer direkt i en virtuell maskin med namnet Dalvik. Nyare versioner av Android använder Android Runtime (ART), som behandlar dex
filer som en mellanliggande representation och utför ytterligare sammanställningar på den innan applikationen körs.
Dex är ett mycket gammalt filformat, vad gäller smarttelefonens livslängd, och designades för enheter vars huvudminne uppmättes i tiotals megabyte. Dessa dags designbegränsningar har förblivit hos oss till denna dag.
Problemet:
dex
filformatet kodar en gräns för antalet metoder som kan hänvisas till i en enda binär. Eftersom den del av filformatet som lagrar antalet referenser är två byte långt är det maximala antalet 0xFFFF
, eller 65535. Om en applikation innehåller mer än det antalet metodreferenser kommer den inte att kompilera.
Vad du ska göra åt det:
Google har gett en väg runt detta problem, kallad Multidex. Den har kompileringstider och körtidskomponenter. Som namnet antyder kommer den vid kompileringstiden att dela kod mellan en eller flera dex
filer. Vid körning kommer det att lära standard ClassLoader
hur man letar upp klasser från dessa filer.
Denna metod fungerar bra på nyare enheter, men har några väsentliga nackdelar. Det kan öka applikationens starttid dramatiskt och på äldre enheter kan orsaka fel på Application Not Responding
.
Multidex, även om det är effektivt, bör undvikas om möjligt.
Hur man undviker gränsen:
Innan du konfigurerar din app för att möjliggöra användning av 64K eller fler metodreferenser, bör du vidta åtgärder för att minska det totala antalet referenser som anropas av din appkod, inklusive metoder som definieras av din appkod eller bibliotek som ingår. Följande strategier kan hjälpa dig att undvika att träffa dex-referensgränsen:
- Granska appens direkta och transitiva beroenden - Se till att allt stort bibliotekberoende du inkluderar i din app används på ett sätt som överstiger mängden kod som läggs till applikationen. Ett vanligt antimönster är att inkludera ett mycket stort bibliotek eftersom några få verktygsmetoder var användbara. Att minska beroende av appkod kan ofta hjälpa dig att undvika dex-referensgränsen.
- Ta bort oanvänd kod med ProGuard - Konfigurera ProGuard-inställningarna för att din app ska köra ProGuard och se till att du har krympat aktiverat för release-builds. Aktivering av krympning säkerställer att du inte levererar oanvänd kod med dina APK: er.
Den första punkten kräver noggrannhet och disciplin från utvecklarens sida. När man integrerar bibliotek från tredje part måste man beakta bibliotekets storlek. Två populära JSON-bibliotek är till exempel Jackson och Gson. Funktionellt sett är de ganska lika, men Gson brukar se större användning i Android. En anledning är att Jackson väger cirka 9 000 metoder, medan Gson bidrar med 1 900.
Det finns flera verktyg som hjälper utvecklare att hålla reda på storleken på sin applikation:
- dexcount-gradle-plugin rapporterar antalet metodreferenser i din APK eller AAR för varje build
- dex-method-counts är ett kommandoradsverktyg som räknar antalet metodreferenser i en APK
- www.methodscount.com är en webbtjänst som räknar metodreferenser i alla APK som du laddar upp.
Multidex genom att använda MultiDexApplication direkt
Använd det här alternativet om du inte behöver en underklass för Application
.
Detta är det enklaste alternativet, men på det här sättet kan du inte ange din egen Application
. Om en underklass för Application
behövs måste du byta till ett av de andra alternativen för att göra det.
För det här alternativet anger du helt enkelt klassens android.support.multidex.MultiDexApplication
för android.support.multidex.MultiDexApplication
android:name
för application
i 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 genom att utöka applikationen
Använd det här alternativet om ditt projekt kräver en underklass för Application
.
Ange denna underklass för Application
med egenskapen android:name
i manifestfilen i application
.
I underklassen för Application
lägger attachBaseContext()
metoden attachBaseContext()
åsidosättande och kallar MultiDex.install()
i den metoden:
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);
}
}
Se till att underklassen för Application
anges i application
i din AndroidManifest.xml:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>
Aktivera Multidex
För att aktivera en multidex-konfiguration behöver du:
- för att ändra din Gradle build-konfiguration
- att använda en
MultiDexApplication
eller aktivera MultiDex i dinApplication
Gradle konfiguration
app/build.gradle
till dessa delar i app/build.gradle
:
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'
}
Aktivera MultiDex i din applikation
Fortsätt sedan med ett av tre alternativ:
När dessa konfigurationsinställningar läggs till i en app konstruerar Android build-verktygen en primär dex (klasser.dex) och stöder (klasser2.dex, klasser3.dex) efter behov.
Byggsystemet kommer sedan att paketera dem i en APK-fil för distribution.
Räknemetodreferenser för varje byggnad (Dexcount Gradle Plugin)
Dexcount-plugin räknar metoder och klassresursantal efter en framgångsrik byggnad.
Lägg till plugin i app/build.gradle
:
apply plugin: 'com.android.application'
buildscript {
repositories {
mavenCentral() // or jcenter()
}
dependencies {
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.5.5'
}
}
Använd plugin i app/build.gradle
filen:
apply plugin: 'com.getkeepsafe.dexcount'
Leta efter utgångsdata som genereras av plugin-programmet:
../app/build/outputs/dexcount
Speciellt användbart är .html-diagrammet i:
../app/build/outputs/dexcount/debugChart/index.html
Multidex genom att utöka MultiDexApplication
Detta liknar mycket att använda en underklass för Application
och åsidosätta attachBaseContext()
.
Men med den här metoden behöver du inte åsidosätta attachBaseContext()
eftersom det redan är gjort i MultiDexApplication
superklass.
MultiDexApplication
istället för 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()
//..........
}
Lägg till den här klassen till din AndroidManifest.xml precis som om du utvidgar applikationen:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>