Demasiadas clases en –main-dex-list, la capacidad principal dex excedida

Estoy intentando ejecutar casos de prueba de instrumentación pero obtengo el siguiente error mientras conversión dex EXCEPCIÓN DE NIVEL SUPERIOR INESPERADA:

com.android.dex.DexException: Too many classes in --main-dex-list, main dex capacity exceeded at com.android.dx.command.dexer.Main.processAllFiles(Main.java:494) at com.android.dx.command.dexer.Main.runMultiDex(Main.java:334) at com.android.dx.command.dexer.Main.run(Main.java:244) at com.android.dx.command.dexer.Main.main(Main.java:215) at com.android.dx.command.Main.main(Main.java:106) :App:dexDebug FAILED 

¿Cómo resolver este problema en gradle?

Primero, comprendamos el problema:

En dispositivos pre-Lollipop, solo el dex principal está siendo cargado por el framework. Para admitir aplicaciones de varios dígitos, debe aplicar un parche explícito al cargador de clases de aplicaciones con todos los archivos dex secundarios (esta es la razón por la cual su clase de Aplicación debe extender la clase MultiDexApplication o llamar a MultiDex # install ).

Esto significa que el dex principal de su aplicación debe contener todas las clases que son potencialmente accesibles antes del parche del cargador de clases.

Recibirá java.lang.ClassNotFoundException si el código de su aplicación intentará hacer referencia a una clase que se empaquetó en uno de sus archivos dex secundarios antes de aplicar parches exitosamente al cargador de clases de aplicaciones.

He documentado aquí cómo el complemento decide qué clases deberían empaquetarse en main-dex.
Si la cantidad total de métodos a los que hacen referencia estas clases excede el límite de 65.536, la comstackción fallará con Too many classes in --main-dex-list, main dex capacity exceeded error.

Puedo pensar en tres soluciones posibles para este problema:

  1. (La solución más fácil, pero no apta para la mayoría de las aplicaciones) Cambie su minSdkVersion a 21.
  2. Reducir el código de su aplicación. Esto fue discutido muchas veces anteriormente (ver aquí y aquí ).
  3. Si ninguna de las soluciones anteriores funciona para usted, puede intentar usar mi solución alternativa para este problema: estoy aplicando el parche de Android gradle para no incluir clases de actividad en dex principal. Es un poco hacky, pero funciona bien para mí.

Hay un problema en el rastreador de errores de Android con respecto a este error. Con suerte, el equipo de herramientas proporcionará una mejor solución pronto.


Actualización (27/4/2016)

La versión 2.1.0 del complemento Gradle permite filtrar las clases de la lista principal-dex.
Advertencia: esto está usando una API no compatible que se reemplazará en el futuro.

Por ejemplo, para excluir todas las clases de actividad, puede hacer lo siguiente:

 afterEvaluate { project.tasks.each { task -> if (task.name.startsWith('collect') && task.name.endsWith('MultiDexComponents')) { println "main-dex-filter: found task $task.name" task.filter { name, attrs -> def componentName = attrs.get('android:name') if ('activity'.equals(name)) { println "main-dex-filter: skipping, detected activity [$componentName]" return false } else { println "main-dex-filter: keeping, detected $name [$componentName]" return true } } } } } 

También puede verificar mi proyecto de ejemplo que demuestra este problema (y aplica el filtrado anterior).


Actualización 2 (01/07/2016)

La versión 2.2.0-alpha4 del complemento Gradle (con build-tools v24) finalmente resuelve este problema al reducir la lista de mantenimiento multidex al mínimo .
El filtro no soportado (y no documentado) de 2.1.0 ya no se debe usar. Actualicé mi proyecto de muestra , demostrando que la comstackción tiene éxito ahora sin ninguna lógica de comstackción personalizada.

Otra forma de resolver este problema es eliminar clases con anotaciones en tiempo de ejecución del archivo DEX principal:

 android { dexOptions { keepRuntimeAnnotatedClasses false } } 

Esto es particularmente útil para las aplicaciones que utilizan marcos de dependency injections, ya que incluso las anotaciones de Dagger generalmente se mantienen en tiempo de ejecución.

Tienes dos opciones.

  1. use ProGuard para quitar el número de métodos
  2. usar la función multidex

Mi consejo: ve con ProGuard, requiere tan poco como cero cambios en el código fuente