Android
Multidex en de limiet van Dex-methode
Zoeken…
Invoering
DEX betekent uitvoerbare bytecode-bestanden van de Android-app (APK) in de vorm van Dalvik Executable (DEX) -bestanden, die de gecompileerde code bevatten die wordt gebruikt om uw app uit te voeren.
De uitvoerbare specificatie van Dalvik beperkt het totale aantal methoden waarnaar binnen een enkel DEX-bestand kan worden verwezen tot 65.536 (64 K) - inclusief Android-frameworkmethoden, bibliotheekmethoden en methoden in uw eigen code.
Om deze limiet te overwinnen, moet u uw app-buildproces configureren om meer dan één DEX-bestand te genereren, ook wel Multidex genoemd.
Opmerkingen
Wat is Dex?
Dex is de naam van het bestandsformaat en de codering waarmee Android Java-code is gecompileerd. Vroege versies van Android laadden dex
binaries rechtstreeks in een virtuele machine met de naam Dalvik. Meer recente versies van Android gebruiken de Android Runtime (ART), die dex
bestanden behandelt als een tussentijdse weergave en verdere compilaties daarop uitvoert voordat de toepassing wordt uitgevoerd.
Dex is een heel oud bestandsformaat, in termen van de levensduur van smartphones, en werd ontworpen voor apparaten waarvan het hoofdgeheugen werd gemeten in tientallen megabytes. De ontwerpbeperkingen van die dagen zijn tot op de dag van vandaag bij ons gebleven.
Het probleem:
De dex
bestandsindeling codeert een limiet voor het aantal methoden waarnaar in één binair bestand kan worden verwezen. Omdat het deel van de bestandsindeling waarin het aantal referenties wordt opgeslagen twee bytes lang is, is het maximale aantal methodeverwijzingen 0xFFFF
of 65535. Als een toepassing meer dan dat aantal methodeverwijzingen bevat, kan deze niet worden gecompileerd.
Wat eraan te doen:
Google heeft dit probleem omzeild, Multidex genoemd. Het heeft compilatie- en runtime-componenten. Zoals de naam al aangeeft, zal het tijdens het compileren code verdelen over een of meer dex
bestanden. Tijdens runtime leert het de standaard ClassLoader
hoe klassen uit deze bestanden kunnen worden ClassLoader
.
Deze aanpak werkt goed op nieuwere apparaten, maar heeft een aantal belangrijke nadelen. Het kan de opstarttijd van de applicatie aanzienlijk verhogen en op oudere apparaten kan de Application Not Responding
fouten.
Multidex, hoewel effectief, moet indien mogelijk worden vermeden.
Hoe de limiet te vermijden:
Voordat u uw app configureert om 64K of meer methodereferenties te gebruiken, moet u stappen ondernemen om het totale aantal referenties te verminderen dat wordt aangeroepen door uw app-code, inclusief methoden die zijn gedefinieerd door uw app-code of opgenomen bibliotheken. De volgende strategieën kunnen u helpen voorkomen dat u de dex-referentielimiet bereikt:
- Controleer de directe en transitieve afhankelijkheden van uw app - Zorg ervoor dat elke grote bibliotheekafhankelijkheid die u in uw app opneemt, wordt gebruikt op een manier die zwaarder weegt dan de hoeveelheid code die aan de toepassing wordt toegevoegd. Een veel voorkomend antipatroon is het opnemen van een zeer grote bibliotheek omdat enkele bruikbare methoden nuttig waren. Door de afhankelijkheid van uw app-code te verminderen, kunt u vaak de dex-referentielimiet vermijden.
- Verwijder ongebruikte code met ProGuard - Configureer de ProGuard-instellingen voor uw app om ProGuard uit te voeren en zorg ervoor dat krimpen is ingeschakeld voor releasebuilds. Als u krimpen inschakelt, zorgt u ervoor dat u geen ongebruikte code met uw APK's verzendt.
Het eerste punt vereist ijver en discipline van de kant van de ontwikkelaar. Bij het opnemen van externe bibliotheken moet rekening worden gehouden met de grootte van de bibliotheek. Twee populaire JSON-bibliotheken zijn bijvoorbeeld Jackson en Gson. Functioneel lijken ze redelijk op elkaar, maar Gson wordt vaker gebruikt in Android. Een reden is dat Jackson ongeveer 9.000 methoden weegt, terwijl Gson 1.900 bijdraagt.
Er zijn verschillende tools beschikbaar waarmee ontwikkelaars de grootte van hun applicatie kunnen bijhouden:
- dexcount-gradle-plugin rapporteert het aantal methodeverwijzingen in uw APK of AAR bij elke build
- dex-method-counts is een opdrachtregelprogramma dat het aantal methodeverwijzingen in een APK telt
- www.methodscount.com is een webservice die de methodeverwijzingen telt in elke APK die u uploadt.
Multidex door MultiDexApplication rechtstreeks te gebruiken
Gebruik deze optie als u geen behoefte Application
subklasse.
Dit is de eenvoudigste optie, maar op deze manier kunt u geen eigen Application
opgeven. Als een Application
nodig is, moet u hiervoor overschakelen naar een van de andere opties.
Geef voor deze optie eenvoudig de volledig gekwalificeerde klassenaam android.support.multidex.MultiDexApplication
voor de android:name
eigenschap van de application
in de 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 door toepassing uit te breiden
Gebruik deze optie als uw project een Application
vereist.
Geef deze Application
met de eigenschap android:name
in het manifestbestand in de application
.
Voeg in de subklasse Application
de methode attachBaseContext()
toe en attachBaseContext()
in die methode 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);
}
}
Zorg ervoor dat de Application
is opgegeven in de application
van uw AndroidManifest.xml:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>
Multidex inschakelen
Om een multidex-configuratie in te schakelen, hebt u het volgende nodig:
- om uw Gradle-buildconfiguratie te wijzigen
- om een
MultiDexApplication
te gebruiken of de MultiDex in uwApplication
in te schakelen
Gradle-configuratie
Voeg in app/build.gradle
deze onderdelen toe:
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'
}
Schakel MultiDex in uw applicatie in
Ga vervolgens verder met een van de drie opties:
Wanneer deze configuratie-instellingen aan een app worden toegevoegd, construeren de Android-buildhulpmiddelen een primaire dex (klassen.dex) en, indien nodig, ondersteunende (klassen2.dex, klassen3.dex).
Het buildsysteem verpakt ze vervolgens in een APK-bestand voor distributie.
Telmethode Referenties bij elke build (Dexcount Gradle Plugin)
De dexcount plug-in telt methoden en klasse resource counts na een succesvolle build.
Voeg de plug-in toe aan de app/build.gradle
:
apply plugin: 'com.android.application'
buildscript {
repositories {
mavenCentral() // or jcenter()
}
dependencies {
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.5.5'
}
}
Pas de plug-in toe in het app/build.gradle
bestand:
apply plugin: 'com.getkeepsafe.dexcount'
Zoek naar de uitvoergegevens die door de plug-in zijn gegenereerd:
../app/build/outputs/dexcount
Vooral handig is de .html-grafiek in:
../app/build/outputs/dexcount/debugChart/index.html
Multidex door MultiDexApplication uit te breiden
Dit lijkt erg op het gebruik van een Application
subklasse en het overschrijven van de methode attachBaseContext()
.
Met deze methode hoeft u attachBaseContext()
echter niet te overschrijven attachBaseContext()
omdat dit al in de superklasse MultiDexApplication
is gebeurd.
MultiDexApplication
uitbreiden MultiDexApplication
plaats van de 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()
//..........
}
Voeg deze klasse toe aan uw AndroidManifest.xml precies alsof u de toepassing zou uitbreiden:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>