1. 程式人生 > >android 中的動態加載

android 中的動態加載

print mpat tag loader setfile 日誌 pro bool 就會

這裏所說的動態加載是加載一個包(插件),其實就是一個 apk只是這個apk 動態加載而已。
創建一個要動態加載的 apk(插件)
寫一個類用於動態加載
//DynamicTest.java

package com.example.liuhailong.idynamic;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
public class DynamicTest {
    public void showPluginWindow(Context context) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setMessage("我是插件的對話框");
        builder.setTitle(R.string.app_name);
        builder.setNegativeButton("取消", new Dialog.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        Dialog dialog = builder.create();
        dialog.show();
    }
}

技術分享圖片
其時就是一個工程可以運行
技術分享圖片
再創建一個工程
把剛才編譯的 apk 放到 assets 目錄下
assets創建:
技術分享圖片
技術分享圖片
先搞清動態加載其實就是把 apk 加載到內存所以有讀apk,寫入的操作
定義一個讀 apk 的類,把 apk 寫入sdcard的文件
//Utils.java

package com.example.liuhailong.testplugin;

import android.content.Context;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Utils {

    private static final int BUF_SIZE = 2048;

    /**
     * 將插件資源從assets寫入到sdcard上
     * @param context 上下文
     * @param assetFile asset目錄下的文件名稱
     * @param sdCardPath 要寫入到sdcard的文件
     */
    public static boolean prepareDex(Context context, String assetFile, File sdCardPath) {
        BufferedInputStream bis = null;
        OutputStream dexWriter = null;
        try {
            bis = new BufferedInputStream(context.getAssets().open(assetFile));
            dexWriter = new BufferedOutputStream(new FileOutputStream(sdCardPath));
            byte[] buf = new byte[BUF_SIZE];
            int len;
            while ((len = bis.read(buf, 0, BUF_SIZE))>0) {
                dexWriter.write(buf, 0, len);
            }
            dexWriter.close();
            bis.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
}

再寫主函數動態加載

package com.example.liuhailong.testplugin;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.content.Context;
import android.os.Bundle;
import android.view.View;

import java.io.File;
import java.lang.reflect.Method;

import dalvik.system.DexClassLoader;

public class MainActivity extends AppCompatActivity {

    private static String TAG = "MainActivity";

    //apk文件存放的路徑
    private String dexFilePath;

    //解壓出dex存儲路徑
    private File dexFile;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e(TAG, "當前的classloader:" + getClassLoader());
        Log.e(TAG, "系統的classloader:" + ClassLoader.getSystemClassLoader());
        //設置dexFilePath
        dexFilePath = getExternalFilesDir(null).getPath() + File.separator + "plugin.apk";
        System.out.println("dexFilePath:" + dexFilePath);
        dexFile = getDir("dex", 0);
        boolean success = Utils.prepareDex(this, "PluginDemo.apk", new File(dexFilePath));
        if (!success)
            return;
        //創建DexClassLoader
        final DexClassLoader dexClassLoader = new DexClassLoader(dexFilePath, dexFile.getAbsolutePath(), null, getClassLoader());
        findViewById(R.id.open_plug_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Class mClass = dexClassLoader.loadClass("com.example.liuhailong.idynamic.DynamicTest");
                    Log.e(TAG,"mClass的默認classLoader:"+mClass.getClassLoader());
                    Object dynamicTest = mClass.newInstance();
                    Method mMethod = mClass.getDeclaredMethod("showPluginWindow", new Class<?>[]{Context.class});
                    mMethod.setAccessible(true);
                    mMethod.invoke(dynamicTest, MainActivity.this);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

技術分享圖片
運行:
技術分享圖片
點擊就會自動加載:
技術分享圖片
日誌:
技術分享圖片

android 中的動態加載