0%

综合技术(三):Android 的动态加载技术

1. 动态加载技术概述

  • 动态加载技术又称插件化技术
  • 插件化可以减轻应用的内存CPU 占用以及 apk 包体积大小,还可以实现热插拔,即不发布新版本的情况下更新某些模块
  • 插件化技术必须要解决的三个基础性问题
    • 资源访问
    • Activity 生命周期管理
    • ClassLoader 的管理

2. 宿主和插件的概念

  • 宿主是指普通的 apk,插件一般是指经过处理的 dex 或者 apk
  • 主流的插件化框架中多采用经过特殊处理的 apk 来作为插件,处理方式往往和编译以及打包环节有关
  • 很多插件化框架都需要用到代理 Activity 的概念,插件 Activity 的启动大多数是借助一个代理 Activity 来实现的

3. 插件化技术之资源访问

  1. 加载 apk 中的资源

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    protected void loadResources() {
    try {
    AssetManager assetManager = AssetManager.class.newInstance();
    Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
    addAssetPath.invoke(assetManger, mDexPath);
    mAssetManger = assetManager;
    } catch (Exception e) {
    e.printStackTrace();
    }
    Resource superRes = super.getResources();
    mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
    mTheme = mResources.newTheme();
    mTheme.setTo(super.getTheme());
    }
  2. 在代理 Activity 中实现 getAssets()getResources()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Override
    public AssetManager getAssets() {
    return mAssetManager == null ? super.getAssets() : mAssetManager;
    }

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

4. 插件化技术之 Activity 生命周期的管理

  • 反射方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    @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.printStackTace();
    }
    }
    super.onPause();
    }
    • 使用反射来管理插件 Activity 的生命周期有两个缺点:一是反射代码写起来比较复杂;二是过多使用反射会有一定的性能开销
  • 接口方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // 声明 DLPlugin
    public interface DLPlugin {
    public void onStart();
    public void onRestart();
    public void onActivityResult(int requestCode, int resultCode, Intent data);
    public void onResume();
    public void onPause();
    public void onStop();
    public void onDestroy();
    public void onCreate(Bundle savedInstanceState);
    public void setProxy(Activity proxyActivity, String dexPath);
    public void onSaveInstanceState(Bundle outState);
    public void onNewIntent(Intent intent);
    public void onRestoreInstanceState(Bundle savedInstanceState);
    public boolean onTouchEvent(MotionEvent event);
    public boolean onKeyUp(int keyCode, KeyEvent event);
    public void onWindowAttributesChanged(LayoutParams params);
    public void onWindowFocusChanged(boolean hasFocus);
    public void onBackPressed();
    ...
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 代理 Activity
    ...
    @Override
    protected void onStart() {
    mRemoteActivity.onStart();
    super.onStart();
    }

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

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

5. 插件化技术之插件 ClassLoader 的管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 为了更好地对多插件进行支持,需要合理地去管理各个插件的 DexClassLoader
// 从而避免多个 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);
}

/**
* return a available classloader which belongs to different apk
*/
public static DLClassLoader getClassLoader(String dexPath, Context context, ClassLoader parentLoader) {
DLClassLoader dlClassLoader = mPluginClassLoaders.get(dexPath);
if (dLClassLoader != 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;
}
}
-------------------- 本文结束感谢您的阅读 --------------------