Android DexClassLoader動態加載與插件化開發

參考連接:java

Dex65536
android

解決Android單個dex文件不能超過65536個方法問題git

Android dex分包方案github


1、 基本概念和注意點
windows

    1.1  首先須要瞭解一點:在Android中能夠動態加載,但沒法像Java中那樣方便動態加載jar網絡

      緣由:Android的虛擬機(Dalvik VM)是不認識Java打出jar的byte code,須要經過dx工具來優化轉換成Dalvik byte code才行。這一點在我們Android項目打包的apk中能夠看出:引入其餘Jar的內容都被打包進了classes.dex。
ide

      因此這條路不通,請你們注意。工具

 

    1.2  當前哪些API可用於動態加載優化

      1.2.1  DexClassLoaderthis

        這個能夠加載jar/apk/dex,也能夠從SD卡中加載,也是本文的重點。

      1.2.3  PathClassLoader  

        只能加載已經安裝到Android系統中的apk文件。

 2、 準備

    本文主要參考"4、參考文章"中第一篇文章,補充細節和實踐過程。

    2.1  下載開源項目

      http://code.google.com/p/goodev-demo

      將項目導入工程,工程報錯的話應該是少了gen文件夾,手動添加便可。注意這個例子是從網上下載優化好的jar(已經優化成dex而後再打包成的jar)到本地文件系統,而後再從本地文件系統加載並調用的。本文則直接改爲從SD卡加載。

 

  3、實踐 

    3.1  編寫接口和實現

      3.1.1  接口IDynamic

package com.dynamic;
public interface IDynamic {
public String helloWorld();
}

3.1.2  實現類DynamicTest

package com.dynamic;

public class DynamicTest implements IDynamic {

    @Override
    public String helloWorld() {
        return "Hello World!";
    }
}

 3.2  打包並轉成dex

      3.2.1  選中工程,常規流程導出便可,如圖:


    注意:在實踐中發現,本身新建一個Java工程而後導出jar是沒法使用的,這一點你們能夠根據文章一來了解相關緣由,也是本文的重點之一。這裏打包導出爲dynamic.jar

      (後期修復:打包請不要把接口文件打進來,參見文章末尾後續維護!)

      3.2.2  將打包好的jar拷貝到SDK安裝目錄android-sdk-windows\platform-tools下,DOS進入這個目錄,執行命名:

dx --dex --output=test.jar dynamic.jar

  3.3  修改調用例子

      修改MainActivity,以下:

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mToastButton = (Button) findViewById(R.id.toast_button);
        
        // Before the secondary dex file can be processed by the DexClassLoader,
        // it has to be first copied from asset resource to a storage location.
//        final File dexInternalStoragePath = new File(getDir("dex", Context.MODE_PRIVATE),SECONDARY_DEX_NAME);
//        if (!dexInternalStoragePath.exists()) {
//            mProgressDialog = ProgressDialog.show(this,
//                    getResources().getString(R.string.diag_title), 
//                    getResources().getString(R.string.diag_message), true, false);
//            // Perform the file copying in an AsyncTask.
//            // 從網絡下載須要的dex文件
//            (new PrepareDexTask()).execute(dexInternalStoragePath);
//        } else {
//            mToastButton.setEnabled(true);
//        }
        
        mToastButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                // Internal storage where the DexClassLoader writes the optimized dex file to.
                //final File optimizedDexOutputPath = getDir("outdex", Context.MODE_PRIVATE);
                final File optimizedDexOutputPath = new File(Environment.getExternalStorageDirectory().toString()
                    + File.separator + "test.jar");
                // Initialize the class loader with the secondary dex file.
//                DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),
//                        optimizedDexOutputPath.getAbsolutePath(),
//                        null,
//                        getClassLoader());
                DexClassLoader cl = new DexClassLoader(optimizedDexOutputPath.getAbsolutePath(),
                    Environment.getExternalStorageDirectory().toString(), null, getClassLoader());
                Class libProviderClazz = null;
                
                try {
                    // Load the library class from the class loader.
                    // 載入從網絡上下載的類
//                    libProviderClazz = cl.loadClass("com.example.dex.lib.LibraryProvider");
                    libProviderClazz = cl.loadClass("com.dynamic.DynamicTest");
 
                    //LibraryInterface lib = (LibraryInterface) libProviderClazz.newInstance();
                    IDynamic lib = (IDynamic)libProviderClazz.newInstance();
                    
                    // Display the toast!
                    //lib.showAwesomeToast(view.getContext(), "hello 世界!");
                    Toast.makeText(MainActivity.this, lib.helloWorld(), Toast.LENGTH_SHORT).show();
                } catch (Exception exception) {
                    // Handle exception gracefully here.
                    exception.printStackTrace();
                }
            }
        });
    }


相關文章
相關標籤/搜索