1. 程式人生 > >Android 使用代理載入外掛

Android 使用代理載入外掛

public class PluginActivity extends Activity implements Attachable {
    public static final String TAG=new String("PluginActivity");
    private Activity mProxyActivity;
@Override
public void attach(Activity activity) {
this.mProxyActivity=activity;
}
@Override
    public View findViewById(int id) {
        return mProxyActivity.findViewById(id);
    }
public void onCreate(Bundle paramBundle){
        mProxyActivity.setContentView(R.layout.plugin_layout);
        mImgView=(ImageView) mProxyActivity.findViewById(R.id.pic);
        mImgView.setImageResource(R.drawable.imgd);
        mButton1=(Button) mProxyActivity.findViewById(R.id.button1);
        mButton2=(Button) mProxyActivity.findViewById(R.id.button2);
        mButtond=(Button) mProxyActivity.findViewById(R.id.buttond);
        mButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mImgView.setImageResource(R.drawable.img1);
            }
        });
        mButton2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mImgView.setImageResource(R.drawable.img2);
            }
        });
        mButtond.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mImgView.setImageResource(R.drawable.imgd);
            }
        });

    }
    @Override
    public void setContentView(int layoutResID){
        mProxyActivity.setContentView(layoutResID);
    }
    @Override
    public void onDestroy() {    }
    @Override
    public void onPause() {    }
    @Override
    public void onRestart() {    }
    @Override
    public void onResume() {    }
    @Override
    public void onStart() {}
    @Override
    public void onStop() {}
}

外掛Activity只是簡單的實現了點選Button,並切換圖片的功能。可以看到,在其內部,所有的動作都是由代理Activity來替它完成的。這就是使用代理進行動態載入的基本思想

9  代理Activity的實現,並管理外掛的生命週期

public class ProxyActivity extends Activity{
private ProxyActivity mSelf;
private Attachable mPluginActivity;
private AssetManager mAssetManager;
private Resources mResources;
//………
//……其他的成員變數

@Override
public Resources getResources() {
    return mResources==null ? super.getResources():mResources;
}
private PackageInfo getUninstalledApkInfo(String archiveFilePath){//上文中已實現………… }

private boolean initPlugin(){  //上文中已實現………… }

private void loadResources(){  //上文中已實現………… }

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSelf=this;
    if (!loadApk("plugindemo.apk")){
	//載入apk出現問題時,呼叫setContentView,將頁面轉置出錯狀態
        setContentView(R.layout.load_plugin_error);
        return;
    }
    if (!initPlugin()){
//初始化外掛出問題時,呼叫setContentView,將頁面轉置出錯狀態
        setContentView(R.layout.load_plugin_error);
        return;
    }
}

private boolean loadApk(String apkFile){
//獲取sdcard上apk包的完整路徑
mApkPath=Environment.getExternalStorageDirectory().getAbsolutePath()+ 
					File.separator+apkFile;

mPkgInfo=getUninstalledApkInfo(mApkPath);
if (mPkgInfo==null){
    Log.d(TAG, "loadApk: can't get package information");
    return false;
}

//獲取apk包中package的名稱
String packageName=mPkgInfo.packageName;
//建立DexClassLoader的優化目錄,在機器的內部儲存中
File optimizedDirectoryFile=mSelf.getDir("dex", Context.MODE_PRIVATE);
DexClassLoader dexClassLoader=new DexClassLoader(mApkPath,optimizedDirectoryFile.toString(),null,mSelf.getClassLoader());
try {
    mPluginClass=dexClassLoader.loadClass(packageName+".PluginActivity");
} catch (ClassNotFoundException e) {
    Log.d(TAG, "loadApk: loading class errors.");
    e.printStackTrace();
    return false;
}

//獲取apk資源
loadResources();
if (mResources==null){
    return false;
}

Log.d(TAG, "loadApk: load apk successfully.");
return true;

}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mPluginActivity!=null)
        mPluginActivity.onDestroy();
}
@Override
protected void onStart() {
    super.onStart();
    if (mPluginActivity!=null)
        mPluginActivity.onStart();
}
//  其餘的生命週期方法不再一一列出……………
//……………………………

上述即為代理Activity的實現。在onCreate中進行了apk的載入和外掛的初始化。若出錯則將Activity顯示為出錯介面。

可以看到,通過代理Activity的生命週期方法間接的呼叫了外掛Activity的生命週期方法。從而實現了代理“套殼”的作用。

效果

內建sdcard裡外部儲存中存放外掛apk的位置,sdcard的根目錄下:

執行效果: