Android
Multidex y el método Dex Limit
Buscar..
Introducción
DEX significa archivos de código de bytes ejecutables de la aplicación de Android (APK) en forma de archivos ejecutables de Dalvik (DEX), que contienen el código compilado utilizado para ejecutar la aplicación.
La especificación de Dalvik Executable limita el número total de métodos a los que se puede hacer referencia dentro de un solo archivo DEX a 65,536 (64K), incluidos los métodos de marco de Android, los métodos de biblioteca y los métodos en su propio código.
Para superar este límite es necesario configurar el proceso de construcción de su aplicación para generar más de un archivo DEX, conocido como Multidex.
Observaciones
¿Qué es dex?
Dex es el nombre del formato de archivo y la codificación en la que se compila el código Java de Android. Las primeras versiones de Android cargarían y ejecutarían binarios de dex
directamente en una máquina virtual llamada Dalvik. Las versiones más recientes de Android utilizan el Android Runtime (ART), que trata los archivos dex
como una representación intermedia y realiza compilaciones adicionales antes de ejecutar la aplicación.
Dex es un formato de archivo muy antiguo, en términos de la vida útil de los teléfonos inteligentes, y fue diseñado para dispositivos cuya memoria principal se midió en decenas de megabytes. Las limitaciones de diseño de esos días han permanecido con nosotros hasta el día de hoy.
El problema:
El formato de archivo dex
codifica un límite para la cantidad de métodos a los que se puede hacer referencia en un solo binario. Debido a que la parte del formato de archivo que almacena el número de referencias tiene una longitud de dos bytes, el número máximo de referencias de método es 0xFFFF
, o 65535. Si una aplicación contiene más de esa cantidad de referencias de método, no podrá compilarse.
Qué hacer al respecto:
Google ha proporcionado una solución a este problema, llamado Multidex. Tiene componentes en tiempo de compilación y en tiempo de ejecución. Como su nombre lo indica, en tiempo de compilación dividirá el código entre uno o más archivos dex
. En tiempo de ejecución, le enseñará al ClassLoader
predeterminado cómo buscar clases de estos archivos.
Este enfoque funciona bien en dispositivos más nuevos, pero tiene algunos inconvenientes importantes. Puede aumentar dramáticamente el tiempo de inicio de la aplicación, y en dispositivos más antiguos puede causar fallas en la Application Not Responding
.
Multidex, si bien es efectivo, debe evitarse si es posible.
Cómo evitar el límite:
Antes de configurar su aplicación para permitir el uso de 64 K o más referencias de métodos, debe tomar medidas para reducir el número total de referencias a las que llama el código de su aplicación, incluidos los métodos definidos por su código de aplicación o las bibliotecas incluidas. Las siguientes estrategias pueden ayudarlo a evitar alcanzar el límite de referencia de dex:
- Revise las dependencias directas y transitivas de su aplicación : asegúrese de que cualquier dependencia de biblioteca grande que incluya en su aplicación se use de una manera que supere la cantidad de código que se agrega a la aplicación. Un anti-patrón común es incluir una biblioteca muy grande porque algunos métodos de utilidad fueron útiles. Reducir las dependencias del código de la aplicación a menudo puede ayudarlo a evitar el límite de referencia de dex.
- Elimine el código no utilizado con ProGuard : configure los ajustes de ProGuard para que su aplicación ejecute ProGuard y asegúrese de que haya activado el encogimiento para las versiones de lanzamiento. La habilitación de la reducción asegura que no esté enviando código no utilizado con sus APK.
El primer punto requiere diligencia y disciplina por parte del desarrollador. Al incorporar bibliotecas de terceros, se debe considerar el tamaño de la biblioteca. Por ejemplo, dos bibliotecas JSON populares son Jackson y Gson. Funcionalmente son bastante similares, pero Gson tiende a ver un mayor uso en Android. Una razón es que Jackson pesa alrededor de 9,000 métodos, mientras que Gson contribuye con 1,900.
Hay varias herramientas disponibles para ayudar a los desarrolladores a realizar un seguimiento del tamaño de su aplicación:
- dexcount-gradle-plugin informa el número de referencias de métodos en su APK o AAR en cada compilación
- dex-method-count es una herramienta de línea de comandos que cuenta el número de referencias de métodos en un APK
- www.methodscount.com es un servicio web que contará las referencias de los métodos en cualquier APK que cargue.
Multidex utilizando MultiDexApplication directamente
Utilice esta opción si no necesita una subclase de Application
.
Esta es la opción más simple, pero de esta manera no puede proporcionar su propia subclase de Application
. Si se necesita una subclase de Application
, tendrá que cambiar a una de las otras opciones para hacerlo.
Para esta opción, simplemente especifique el nombre de clase completamente calificado android.support.multidex.MultiDexApplication
para la propiedad android:name
de la etiqueta de la application
en el archivo 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 extendiendo la aplicación
Utilice esta opción si su proyecto requiere una subclase de Application
.
Especifique esta subclase de Application
utilizando la propiedad android:name
en el archivo de manifiesto dentro de la etiqueta de la application
.
En la subclase de la Application
, agregue la attachBaseContext()
método attachBaseContext()
, y en ese método llame a 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);
}
}
Asegúrese de que la subclase de la Application
esté especificada en la etiqueta de la application
de su AndroidManifest.xml:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>
Habilitando Multidex
Para habilitar una configuración multidex necesitas:
- para cambiar su configuración de construcción Gradle
- para usar una aplicación
MultiDexApplication
o habilitar MultiDex en su clase deApplication
Configuracion gradle
En app/build.gradle
agregue estas partes:
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'
}
Habilite MultiDex en su aplicación
Luego proceda con una de las tres opciones:
Cuando estos ajustes de configuración se agregan a una aplicación, las herramientas de compilación de Android construyen un dex primario (classes.dex) y el soporte (classes2.dex, classes3.dex) según sea necesario.
El sistema de compilación luego los empaquetará en un archivo APK para su distribución.
Referencias del método de conteo en cada compilación (Dexcount Gradle Plugin)
El complemento de dexcount cuenta los métodos y el recuento de recursos de clase después de una compilación exitosa.
Agregue el complemento en la app/build.gradle
:
apply plugin: 'com.android.application'
buildscript {
repositories {
mavenCentral() // or jcenter()
}
dependencies {
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.5.5'
}
}
Aplique el complemento en el archivo app/build.gradle
:
apply plugin: 'com.getkeepsafe.dexcount'
Busque los datos de salida generados por el complemento en:
../app/build/outputs/dexcount
Especialmente útil es el gráfico .html en:
../app/build/outputs/dexcount/debugChart/index.html
Multidex extendiendo MultiDexApplication
Esto es muy similar a usar una subclase de Application
y anular el método attachBaseContext()
.
Sin embargo, al usar este método, no es necesario que sustituya a attachBaseContext()
ya que esto ya se hizo en la superclase MultiDexApplication
.
Extienda la aplicación MultiDexApplication
lugar de la 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()
//..........
}
Agrega esta clase a tu AndroidManifest.xml exactamente como si estuvieras extendiendo la aplicación:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>