<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ### 13.2 使用multidex來解決方法數越界 在Android中單個dex文件所能夠包含的最大方法數為65536,這包含Android FrameWork、依賴的jar包以及應用本身的代碼中的所有方法。65536是一個很大的數,一般來說一個簡單應用的方法數的確很難達到65536,但是對于一些比較大型的應用來說,65536就很容易達到了。當應用的方法數達到65536后,編譯器就無法完成編譯工作并拋出類似下面的異常: UNEXPECTED TOP-LEVEL EXCEPTION: com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536 at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:502) at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger. java:283) at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:491) at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:168) at com.android.dx.merge.DexMerger.merge(DexMerger.java:189) at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main. java:454) at com.android.dx.command.dexer.Main.runMonoDex(Main.java:303) at com.android.dx.command.dexer.Main.run(Main.java:246) at com.android.dx.command.dexer.Main.main(Main.java:215) at com.android.dx.command.Main.main(Main.java:106) 另外一種情況有所不同,有時候方法數并沒有達到65536,并且編譯器也正常地完成了編譯工作,但是應用在低版本手機安裝時異常中止,異常信息如下: E/dalvikvm: Optimization failed E/installd: dexopt failed on '/data/dalvik-cache/data@app@com.ryg. multidextest-2.apk@classes.dex' res = 65280 為什么會出現這種情況呢?其實是這樣的,dexopt是一個程序,應用在安裝時,系統會通過dexopt來優化dex文件,在優化過程中dexopt采用一個固定大小的緩沖區來存儲應用中所有方法的信息,這個緩沖區就是LinearAlloc。LinearAlloc緩沖區在新版本的Android系統中其大小是8MB或者16MB,但是在Android 2.2和2.3中卻只有5MB,當待安裝的apk中的方法數比較多時,盡管它還沒有達到65536這個上限,但是它的存儲空間仍然有可能超出5MB,這種情況下dexopt程序就會報錯,從而導致安裝失敗,這種情況主要在2.x系列的手機上出現。 可以看到,不管是編譯時方法數越界還是安裝時的dexopt錯誤,它們都給開發過程帶來了很大的困擾。從目前的Android版本的市場占有率來說,Android 3.0以下的手機仍然占據著不到10%的比率,目前主流的應用都不可能放棄Android 3.0以下的用戶,對于這些應用來說,方法數越界就是一個必須要解決的問題了。 如何解決方法數越界的問題呢?我們首先想到的肯定是刪除無用的代碼和第三方庫。沒錯,這的確是必須要做的工作,但是很多情況下即使刪除了無用的代碼,方法數仍然越界,這個時候該怎么辦呢?針對這個問題,之前很多應用都會考慮采用插件化的機制來動態加載部分dex,通過將一個dex拆分成兩個或多個dex,這就在一定程度上解決了方法數越界的問題。但是插件化是一套重量級的技術方案,并且其兼容性問題往往較多,從單純解決方法數越界的角度來說,插件化并不是一個非常適合的方案,關于插件化的意義將在第13.3節中進行介紹。為了解決這個問題,Google在2014年提出了multidex的解決方案,通過multidex可以很好地解決方法數越界的問題,并且使用起來非常簡單。 在Android 5.0以前使用multidex需要引入Google提供的android-support-multidex.jar這個jar包,這個jar包可以在Android SDK目錄下的extras/android/support/multidex/library/libs下面找到。從Android 5.0開始,Android默認支持了multidex,它可以從apk中加載多個dex文件。Multidex方案主要是針對AndroidStudio和Gradle編譯環境的,如果是Eclipse和ant那就復雜一些,而且由于AndroidStudio作為官方IDE其最終會完全替代Eclipse ADT,因此本節中也不再介紹Eclipse中配置multidex的細節了。 在AndroidStudio和Gradle編譯環境中,如果要使用multidex,首先要使用Android SDK Build Tools 21.1及以上版本,接著修改工程中app目錄下的build.gradle文件,在defaultConfig中添加multiDexEnabled true這個配置項,如下所示。關于如何使用AndroidStudio和Gradle請讀者自行查看相關資料,這里不再介紹。 android { compileSdkVersion 22 buildToolsVersion "22.0.1" defaultConfig { applicationId "com.ryg.multidextest" minSdkVersion 8 targetSdkVersion 22 versionCode 1 versionName "1.0" // enable multidex support multiDexEnabled true } ... } 接著還需要在dependencies中添加multidex的依賴:compile 'com.android.support:multidex:1.0.0',如下所示。 dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.1.1' compile 'com.android.support:multidex:1.0.0' } 最終配置完成的build.gradle文件如下所示,其中加粗的部分是專門為multidex所添加的配置項: apply plugin: 'com.android.application' android { compileSdkVersion 22 buildToolsVersion "22.0.1" defaultConfig { applicationId "com.ryg.multidextest" minSdkVersion 8 targetSdkVersion 22 versionCode 1 versionName "1.0" // enable multidex support multiDexEnabled true } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.1.1' compile 'com.android.support:multidex:1.0.0' } 經過了上面的過程,還需要做另一項工作,那就是在代碼中加入支持multidex的功能,這個過程是比較簡單的,有三種方案可以選。 第一種方案,在manifest文件中指定Application為MultiDexApplication,如下所示。 <application android:name="android.support.multidex.MultiDexApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > ... </application> 第二種方案,讓應用的Application繼承MultiDexApplication,比如: public class TestApplication extends MultiDexApplication { … } 第三種方案,如果不想讓應用的Application繼承MultiDexApplication,還可以選擇重寫Application的attachBaseContext方法,這個方法比Application的onCreate要先執行,如下所示。 public class TestApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } } 現在所有的工作都已經完成了,可以發現應用不但可以編譯通過了并且還可以在Android 2.x手機上面正常安裝了。可以發現,multidex使用起來還是很簡單的,對于一個使用multidex方案的應用,采用了上面的配置項,如果這個應用的方法數沒有越界,那么Gradle并不會生成多個dex文件,如果方法數越界后,Gradle就會在apk中打包2個或多個dex文件,具體會打包多少個dex文件要看當前項目的代碼規模。圖13-2展示了采用multidex方案的apk中多個dex的分布情形。 :-: ![](https://img.kancloud.cn/a7/9e/a79eb250cb9c67a028c96fe2a6d6c85a_1349x573.png) 圖13-2 普通apk和采用multidex方案的apk 上面介紹的是multidex默認的配置,還可以通過build.gradle文件中一些其他配置項來定制dex文件的生成過程。在有些情況下,可能需要指定主dex文件中所要包含的類,這個時候就可以通過--main-dex-list選項來實現這個功能。下面是修改后的build.gradle文件,在里面添加了afterEvaluate區域,在afterEvaluate區域內部采用了--main-dex-list選項來指定主dex中要包含的類,如下所示。 apply plugin: 'com.android.application' android { compileSdkVersion 22 buildToolsVersion "22.0.1" defaultConfig { applicationId "com.ryg.multidextest" minSdkVersion 8 targetSdkVersion 22 versionCode 1 versionName "1.0" // enable multidex support multiDexEnabled true } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } afterEvaluate { println "afterEvaluate" tasks.matching { it.name.startsWith('dex') }.each { dx -> def listFile = project.rootDir.absolutePath + '/app/maindexlist.txt' println "root dir:" + project.rootDir.absolutePath println "dex task found: " + dx.name if (dx.additionalParameters == null) { dx.additionalParameters = [] } dx.additionalParameters += '--multi-dex' dx.additionalParameters += '--main-dex-list=' + listFile dx.additionalParameters += '--minimal-main-dex' } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.1.1' compile 'com.android.support:multidex:1.0.0' } 在上面的配置文件中,--multi-dex表示當方法數越界時則生成多個dex文件,--main-dex-list指定了要在主dex中打包的類的列表,--minimal-main-dex表明只有--main-dex-list所指定的類才能打包到主dex中。它的輸入是一個文件,在上面的配置中,它的輸入是工程中app目錄下的maindexlist.txt這個文件,在maindexlist.txt中則指定了一系列的類,所有在maindexlist.txt中的類都會被打包到主dex中。注意maindexlist.txt這個文件名是可以修改的,但是它的內容必須要遵守一定的格式,下面是一個示例,這種格式是固定的。 com/ryg/multidextest/TestApplication.class com/ryg/multidextest/MainActivity.class // multidex android/support/multidex/MultiDex.class android/support/multidex/MultiDexApplication.class android/support/multidex/MultiDexExtractor.class android/support/multidex/MultiDexExtractor$1.class android/support/multidex/MultiDex$V4.class android/support/multidex/MultiDex$V14.class android/support/multidex/MultiDex$V19.class android/support/multidex/ZipUtil.class android/support/multidex/ZipUtil$CentralDirectory.class 程序編譯后可以反編譯apk中生成的主dex文件,可以發現主dex文件的確只有maindexlist.txt文件中所聲明的類,讀者可以自行嘗試。maindexlist.txt這個文件很多時候都是可以通過腳本來自動生成內容的,這個腳本需要根據當前的項目自行實現,如果不采用腳本,人工編輯maindexlist.txt也是可以的。 需要注意的是,multidex的jar包中的9個類必須也要打包到主dex中,否則程序運行時會拋出異常,告知無法找到multidex相關的類。這是因為Application對象被創建以后會在attachBaseContext方法中通過MultiDex.install(this)來加載其他dex文件,這個時候如果MultiDex相關的類不在主dex中,很顯然這些類是無法被加載的,那么程序執行就會出錯。同時由于Application的成員和代碼塊會先于attachBaseContext方法而初始化,而這個時候其他dex文件還沒有被加載,因此不能在Application的成員以及代碼塊中訪問其他dex中的類,否則程序也會因為無法加載對應的類而中止執行。在下面的代碼中,模擬了這種場景,在Application的成員中使用了其他dex文件中的類View1。 public class TestApplication extends Application { private View1 view1 = new View1(); @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } } 上面的代碼會導致如下運行錯誤,因此在實際開發中要避免這個錯誤。 E/AndroidRuntime: FATAL EXCEPTION: main Process: com.ryg.multidextest, PID: 12709 java.lang.NoClassDefFoundError: com.ryg.multidextest.ui.View1 at com.ryg.multidextest.TestApplication.<init>(TestApplication. java:14) at java.lang.Class.newInstanceImpl(Native Method) at java.lang.Class.newInstance(Class.java:1208) at android.app.Instrumentation.newApplication(Instrumentation. java:990) at android.app.Instrumentation.newApplication(Instrumentation. java:975) at android.app.LoadedApk.makeApplication(LoadedApk.java:504) ... Multidex方法雖然很好地解決了方法數越界這個問題,但它也是有一些局限性的,下面是采用multidex可能帶來的問題: (1)應用啟動速度會降低。由于應用啟動時會加載額外的dex文件,這將導致應用的啟動速度降低,甚至可能出現ANR現象,尤其是其他dex文件較大的時候,因此要避免生成較大的dex文件。 (2)由于Dalvik linearAlloc的bug,這可能導致使用multidex的應用無法在Android 4.0以前的手機上運行,因此需要做大量的兼容性測試。同時由于Dalvik linearAlloc的bug,有可能出現應用在運行中由于采用了multidex方案從而產生大量的內存消耗的情況,這會導致應用崩潰。 在實際的項目中,(1)中的現象是客觀存在的,但是(2)中的現象目前極少遇到,綜合來說,multidex還是一個解決方法數越界非常好的方案,可以在實際項目中使用。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看