Android動態加載技術(插件化技術)


No1:

插件化技術的好處

1)減輕應用的內存和CPU占用

2)實現熱插拔,即在不發布新版本的情況下更新某些模塊

No2:

插件化方案必須要解決三個基礎性問題:資源訪問Activity生命周期的管理ClassLoader的管理

No3:

宿主是指普通的apk,插件一般指經過處理的dex或者apk。插件化框架大多采用apk作為插件,很多需要用到代理Activity,插件Activity的啟動大多數是借助一個代理Activity來實現的。

No4:

Activity的工作主要是通過ContextImpl來完成的,Activity中有一個交mBase的成員變量,它的類型就是ContextImpl。Context中有兩個抽象方法getAssetsgetResources,通過它們來獲取資源的,真正實現在ContextImpl中。

No5:

資源訪問

加載apk中的資源

protected void loadResources(){
    try{
        AssetManager assetManager = AssetManager.class.newInstance();
        Method addAssetPath = assetManager.getClass().getMethod("addAssetPath",String.class);
        addAssetPath.invoke(assetManager,mDexPath);
        mAssetManager = assetManager;
    }catch(Exception e){
        e.printStackTrace();
    }
    Resources superRes = super.getResources();
    mResources = new Resources(mAssetManager,superRes.getDisplayMetrics(),superRes.getConfiguration());
    mTheme = mResources.newTheme();
    mTheme.setTo(super.getTheme());
}

通過反射,調用AssetManager中addAssetPath方法,將一個apk中的資源加載到Resources對象中。然后通過AssetManager來創建一個新的Resources對象

public final int addAssetPath(String path){
    synchronized(this){
        int res = addAssetPathNative(path);
        makeStringBlocks(mStringBlocks);
        return res;
    }
}

接着在代理Activity中實現getAssets和getResources

@Override
public AssetManager getAssets(){
    return mAssetManager == null?super.getAssets():mAssetManager;
}

@Override
public Resources getResources(){
    return mResources == null?super.getResources():mResources;
}

No6:

Activity生命周期的管理

反射方式

@Override
protected void onResume(){
    super.onResume();
    Method onResume = mActivityLifecircleMethods.get("onResume");
    if(onResume!=null){
        try{
            onResume.invoke(mRemoteActivity,new Object[]{ })
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

@Override
protected void onPause(){
    Method onPause = mActivityLifecircleMethods.get("onPause");
    if(onPause!=null){
        try{
            onPause.invoke(mRemoteActivity,new Object[]{ })
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    super.onPause();
}

接口方式

public interface DLPlugin{
    public void onStart();
    public void onRestart();
    public void onResume();
    public void onPause();
    public void onStop();
    public void onDestroy();
    ...
}

代理Actvitiy中調用

...
@Override
protected void onStart(){
    mRemoteActivity.onStart();
    super.onStart();
}

@Override
protected void onRestart(){
    mRemoteActivity.onRestart();
    super.onRestart();
}

@Override
protected void onResume(){
    mRemoteActivity.onResume();
    super.onResume();
}

mRemoteActivity就是DLPlugin的實現

No7:

插件ClassLoader的管理

public class DLClassLoader extends DexClassLoader{
    private static final String TAG ="DLClassLoader";
    private static final HashMap<String,DLClassLoader> mPluginClassLoaders = new HashMap<String,DLClassLoader>();
    
    protected DLClassLoader(String dexPath,String optimizedDirectory,String libraryPath,Classloader parent){
        super(dexPath,optimizedDirectory,libraryPath,parent);
    }
    
    public static DLClassLoader getClassLoader(String dexPath,Context context,Classloader parentLoader){
        DLClassLoader dLassLoader = mPluginClassLoaders.get(dexPath);
        if(dLassLoader != null){
            return DLClassLoader;
        }
        
        File dexOutputDir = context.getDir("dex",Context.MODE_PRIVATE);
        final String dexOutputPath = dexOutputDir.getAbsolutePath();
        dLClassLoader = new DLClassLoader(dexPath,dexOutputPath,null,parentLoader);
        mPluginClassLoaders.put(dexPath,dLClassLoader);
        
        return dLClassLoader;
    }
}

 

通過將不同插件的ClassLoader存儲在一個HashMap中,這樣就可以保證不同插件中的類彼此互不干擾。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM