Android
Мультидекс и предел метода Dex
Поиск…
Вступление
DEX означает исполняемые файлы байт-кода Android (APK) в виде файлов Dalvik Executable (DEX), которые содержат скомпилированный код, используемый для запуска вашего приложения.
Спецификация исполняемого файла Dalvik ограничивает общее количество методов, на которые можно ссылаться в одном файле DEX, до 65 536 (64 КБ), включая методы каркаса Android, библиотечные методы и методы в вашем собственном коде.
Чтобы преодолеть этот предел, необходимо настроить процесс сборки приложений для создания более одного файла DEX, известного как Multidex.
замечания
Что такое dex?
Dex - это имя формата файла и кодировки, с которой компилируется код Java Java. Ранние версии Android загружали и исполняли двоичные файлы dex
непосредственно на виртуальной машине Dalvik. В более поздних версиях Android используется Android Runtime (ART), которая обрабатывает файлы dex
как промежуточное представление и выполняет дальнейшие компиляции на нем до запуска приложения.
Dex - очень старый формат файла с точки зрения продолжительности жизни смартфонов и предназначен для устройств, основная память которых измерена в десятках мегабайт. Дизайнерские ограничения тех дней остались с нами по сей день.
Эта проблема:
Формат файла dex
кодирует ограничение на количество методов, на которые можно ссылаться в одном бинарном файле. Поскольку часть формата файла, в которой хранится количество ссылок, составляет два байта, максимальное число ссылок на методы - 0xFFFF
или 65535. Если приложение содержит больше, чем это число ссылок на методы, оно не скомпилируется.
Что с этим делать:
Google предоставил возможность обойти эту проблему, называемую Multidex. Он имеет компоненты времени компиляции и времени выполнения. Как следует из его названия, во время компиляции он будет делить код между одним или несколькими файлами dex
. Во время выполнения он научит стандартного ClassLoader
как искать классы из этих файлов.
Этот подход хорошо работает на новых устройствах, но имеет некоторые существенные недостатки. Это может значительно увеличить время запуска приложений, а на старых устройствах может возникнуть отказ Application Not Responding
.
По возможности следует избегать использования Multidex, хотя и эффективно.
Как избежать ограничения:
Прежде чем настраивать приложение, чтобы разрешить использование ссылок на 64K или более, вы должны предпринять шаги, чтобы уменьшить общее количество ссылок, вызванных вашим кодом приложения, включая методы, определенные вашим кодом приложения или включенными библиотеками. Следующие стратегии помогут вам избежать попадания лимита ссылки dex:
- Просмотрите прямые и транзитивные зависимости вашего приложения. Убедитесь, что любая большая зависимость библиотеки, которую вы включаете в приложение, используется таким образом, чтобы перераспределить количество добавляемого кода в приложение. Общим анти-шаблоном является включение очень большой библиотеки, потому что несколько полезных методов были полезны. Сокращение зависимостей от кода приложения часто помогает избежать ограничения ссылки на dex.
- Удалите неиспользуемый код с помощью ProGuard. Настройте параметры ProGuard для вашего приложения, чтобы запустить ProGuard, и убедитесь, что у вас есть сокращения для релизов. Включение усадки гарантирует, что вы не отправляете неиспользованный код с вашими APK.
Первый момент требует усердия и дисциплины со стороны разработчика. При включении сторонних библиотек следует учитывать размер библиотеки. Например, две популярные библиотеки JSON - это Джексон и Гсон. Функционально они довольно похожи, но Gson имеет тенденцию видеть большее использование в Android. Одна из причин заключается в том, что Джексон весит около 9000 методов, тогда как Gson составляет 1900 человек.
Существует несколько инструментов, помогающих разработчикам отслеживать размер их приложения:
- dexcount-gradle-plugin сообщает количество ссылок на методы в вашем APK или AAR для каждой сборки
- dex-method-counts - это средство командной строки, которое подсчитывает количество ссылок на методы в APK
- www.methodscount.com - это веб-служба, которая будет рассчитывать ссылки на методы в любом APK, который вы загружаете.
Мультидекс с помощью MultiDexApplication напрямую
Используйте этот параметр, если вам не нужен подкласс Application
.
Это самый простой вариант, но таким образом вы не можете предоставить свой собственный подкласс Application
. Если необходим подкласс Application
, вам придется перейти на один из других вариантов, чтобы сделать это.
Для этого параметра просто укажите полное имя класса android.support.multidex.MultiDexApplication
для свойства android:name
тега application
в 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, расширяя приложение
Используйте этот параметр, если для вашего проекта требуется подкласс Application
.
Задайте этот подкласс Application
используя свойство android:name
в файле манифеста внутри тега application
.
В подклассе Application
добавьте переопределение метода attachBaseContext()
, и в этом методе вызовите 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);
}
}
Убедитесь, что подкласс Application
указан в теге application
вашего AndroidManifest.xml:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>
Включение Multidex
Чтобы включить конфигурацию multidex, вам необходимо:
- изменить конфигурацию сборки Gradle
- использовать
MultiDexApplication
или включить MultiDex в своем классеApplication
Конфигурация гребенки
В 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'
}
Включить MultiDex в приложении
Затем выполните один из трех вариантов:
Когда эти настройки конфигурации добавляются в приложение, инструменты сборки Android строят первичный dex (classes.dex) и поддерживают (classes2.dex, classes3.dex) по мере необходимости.
Затем система сборки упаковывает их в файл APK для распространения.
Ссылки метода подсчета на каждом сборке (плагин Gradle Dexcount)
Плагин dexcount подсчитывает методы и количество ресурсов класса после успешной сборки.
Добавьте плагин в app/build.gradle
:
apply plugin: 'com.android.application'
buildscript {
repositories {
mavenCentral() // or jcenter()
}
dependencies {
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.5.5'
}
}
Примените плагин в файле app/build.gradle
:
apply plugin: 'com.getkeepsafe.dexcount'
Ищите выходные данные, сгенерированные плагином:
../app/build/outputs/dexcount
Особенно полезной является диаграмма .html в:
../app/build/outputs/dexcount/debugChart/index.html
Multidex путем расширения MultiDexApplication
Это очень похоже на использование подкласса Application
и переопределение attachBaseContext()
.
Однако, используя этот метод, вам не нужно переопределять attachBaseContext()
поскольку это уже сделано в суперклассе MultiDexApplication
.
Расширьте MultiDexApplication
вместо 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()
//..........
}
Добавьте этот класс в свой AndroidManifest.xml точно так же, как если бы вы расширяли приложение:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>