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中,这样就可以保证不同插件中的类彼此互不干扰。

posted @ 2018-01-24 14:11  嘉禾世兴  阅读(2166)  评论(0编辑  收藏  举报