Android
MultidexとDexメソッドの制限
サーチ…
前書き
DEXは、アプリを実行するために使用されるコンパイルされたコードを含むDalvik Executable(DEX)ファイルの形式でAndroidアプリの(APK)実行可能なバイトコードファイルを意味します。
Dalvik実行ファイル仕様では、DEXファイル内で参照できるメソッドの総数が、独自のコードでAndroidフレームワークメソッド、ライブラリメソッド、およびメソッドを含む65,536(64K)に制限されています。
この制限を克服するには、複数のDEXファイル(Multidex)を生成するようにアプリケーションビルドプロセスを設定する必要があります。
備考
dexとは何ですか?
Dexは、Android Javaコードがコンパイルされるファイル形式とエンコーディングの名前です。 Androidの初期のバージョンでは、Dalvikという仮想マシンにdex
バイナリを直接ロードして実行します。 Androidの最近のバージョンでは、Androidランタイム(ART)が使用されています。これは、 dex
ファイルを中間表現として扱い、アプリケーションを実行する前にそれをさらにコンパイルします。
Dexはスマートフォンの寿命の点で非常に古いファイル形式であり、主メモリが数十メガバイトで測定されたデバイス用に設計されています。当時のデザインの限界が今も残っています。
問題:
dex
ファイル形式は、1つのバイナリで参照できるメソッドの数の制限をエンコードします。参照の数を格納するファイル形式の部分は2バイト長であるため、メソッド参照の最大数は0xFFFF
、つまり65535です。アプリケーションにその数よりも多くのメソッド参照が含まれていると、コンパイルが失敗します。
それについて何をすべきか:
GoogleはMultidexと呼ばれるこの問題を回避する手段を提供しています。コンパイル時および実行時のコンポーネントがあります。その名前が示すように、コンパイル時には、1つ以上のdex
ファイル間でコードを分割します。実行時に、デフォルトのClassLoader
これらのファイルからクラスをルックアップする方法を教えます。
このアプローチは、より新しいデバイスではうまくいくが、いくつかの大きな欠点がある。これにより、アプリケーションの起動時間が大幅に短縮され、古いデバイスではApplication Not Responding
障害が発生する可能性がありApplication Not Responding
。
可能であれば、Multidexは効果的ですが避けてください。
限界を避ける方法:
64K以上のメソッド参照を使用できるようにアプリを設定する前に、アプリコードで呼び出された参照の総数を減らすための手順を実行する必要があります。以下の戦略は、dex参照制限を回避するのに役立ちます。
- アプリの直接的および推移的な依存関係を確認する - アプリケーションに追加する大きなライブラリ依存関係を、アプリケーションに追加するコードの量よりも多く使用するようにします。一般的な反パターンは、いくつかのユーティリティメソッドが有用であったため、非常に大きなライブラリを含めることです。アプリケーションコードの依存関係を減らすと、dex参照の制限を避けることができます。
- ProGuardを使用して未使用のコードを削除する - ProGuardを実行するようにアプリケーションのProGuard設定を構成し、リリースビルドで縮小が有効になっていることを確認します。縮小を有効にすると、未使用のコードをAPKで配送しないようにすることができます。
最初の点は、開発者の側で勤勉と規律を必要とします。サードパーティライブラリを組み込む場合は、ライブラリのサイズを考慮する必要があります。たとえば、人気のあるJSONライブラリの2つは、JacksonとGsonです。機能的にはまったく似ていますが、GsonはAndroidでの使用が増えています。 1つの理由は、ジャクソンが約9,000の方法で体重を測定するのに対し、Gsonは1,900に寄与しているということです。
開発者がアプリケーションのサイズを把握するのに役立つツールがいくつかあります。
- dexcount-gradle-pluginは、各ビルドのAPKまたはAARのメソッド参照の数をレポートします
- dex-method-countsは、APK内のメソッド参照の数を数えるコマンドラインツールです
- www.methodscount.comはアップロードするAPKのメソッド参照を数えるWebサービスです。
MultiDexApplicationを直接使用したMultidex
Application
サブクラスを必要としない場合は、このオプションを使用します。
これは最も簡単なオプションですが、独自のApplication
サブクラスを提供することはできません。 Application
サブクラスが必要な場合は、他のオプションの1つに切り替える必要があります。
このオプションの場合、AndroidManifest.xmlのapplication
タグのandroid:name
プロパティに完全修飾クラス名android.support.multidex.MultiDexApplication
を指定するだけapplication
。
<?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
。
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
サブクラスがAndroidManifest.xmlのapplication
タグで指定されていることを確認します。
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>
マルチディックスの有効化
multidex構成を有効にするには、次のものが必要です。
- あなたのGradleビルド設定を変更する
-
MultiDexApplication
を使用するか、Application
クラスでMultiDexを有効にする
グラデル構成
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を有効にする
次に、3つのオプションのいずれかを実行します。
これらの設定がアプリに追加されると、Androidビルドツールは必要に応じて主要dex(classes.dex)とサポート(classes2.dex、classes3.dex)を構築します。
ビルドシステムは、それらをAPKファイルにパッケージ化して配布します。
すべてのビルドでメソッド参照の数をカウントする(Dexcount Gradle Plugin)
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
MultiDexApplicationを拡張したMultidex
これは、 Application
サブクラスを使用してattachBaseContext()
メソッドをオーバーライドするattachBaseContext()
と非常によく似ています。
ただし、このメソッドを使用すると、 attachBaseContext()
はすでにMultiDexApplication
スーパークラスでオーバーライドされているため、オーバーライドする必要はありません。
Application
代わりにMultiDexApplication
を拡張する:
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>