拓展-组件化、插件化

组件化

AucFrameTemplate

ARouter

组件化和插件化最大区别

组件化在编译期可以动态添加和修改,运行期则不行。
插件化在编译期和运行期都可以动态添加和修改。

组件模块

组件Component是一种工具功能性质,而模块Module具有系统功能性质。例如jetpack中的构架组件。

参考链接

https://juejin.im/post/5e5f2efde51d4526d43f3b99?utm_source=gold_browser_extension

https://juejin.im/post/5e4d2256f265da575918d381#heading-5

安卓组件化之Application

原文链接

Application的定义

  • 代表应用程序(即 Android App)的类,也属于Android中的一个系统组件
  • 继承关系:继承自 ContextWarpper
1
2
3
4
java.lang.Object
->android.content.Context
->android.content.ContextWrapper
->android.app.Application

Application的特点

Application是单例,一个App仅创建唯一一个Application。

其生命周期就是App的生命周期。

Application中常用的回调方法:

  • onCreate:创建应用程序时回调,回调时机早于任何Activity

    作用:

    1. 初始化应用程序级别的资源。如全局对象、环境配置变量、图片资源初始化、推送服务的注册等。

    2. 数据共享、数据缓存

      设置全局共享数据,如全局共享变量、方法等。(App杀死会被清空)

    注意:不要执行耗时操作,否则会拖慢应用程序启动速度。

  • onTerminate:终止应用程序时调用,不能保证一定会被调用(在模拟器上会被调用,真机上不会被调用)

1
2
3
4
5
6
7
8
9
10
11
12
// registerComponentCallbacks() & unregisterComponentCallbacks()
//作用注册和注销ComponentCallbacks2回调接口
registerComponentCallbacks(new ComponentCallbacks2() {
@Override
public void onTrimMemory(int level) {}

@Override
public void onLowMemory() {}

@Override
public void onConfigurationChanged(Configuration newConfig) {}
});
  • onLowmemory:当后台应用程序终止,但前台应用程序内存不够,可在此方法内做些资源释放的操作。

  • onConfigurationChanged:配置发生时回调,如屏幕旋转灯。

  • onTrimMemory:通知应用的不同内存情况(以内存级别进行识别)

内存使用情况 级别
(级别越高越严重)
含义
TRIM_MEMORY_RUNNING_MODERATE 内存不足级别:5
状态:应用程序处于前台运行
含义:应用程序正常运行,不会被杀掉。但当前内存有点低,系统开始杀死其他进行后台应用程序
TRIM_MEMORY_RUNNING_LOW 内存不足级别:10
状态:应用程序处于前台运行
含义:应用程序正常运行,不会被杀掉。但当前内存非常低了,请必须释放你自身不必要的内存,否则会影响应用程序的性能你(如响应速度等等)
TRIM_MEMORY_RUNNING_CRITICAL 内存不足级别:15
状态:应用程序处于前台运行
含义:应用程序正常运行,但大部分其他后台程序已被杀死,请务必释放你自身不必要的内存,否则你也会被杀死。
TRIM_MEMORY_UI_HIDDEN 内存不足级别:20
状态:应用程序处于前台运行
含义:系统内存已经非常低了,并将该应用程序从前台切换到后台,即收回UI资源
TRIM_MEMORY_BACKGROUND 内存不足级别:40
状态:应用程序处于后台缓存
含义:系统内存已经较低了,该应用程序处于LRU缓存列表的最近位置,但不会被清理掉。此时应用释放掉一些较容易恢复的资源让手机的内存变得充足,从而让我们的程序更长时间地保留在缓存当中
TRIM_MEMORY_MODERATE 内存不足级别:60
状态:应用程序处于后台缓存
含义:系统内存已经非常低了,该应用程序处于LRU缓存列表的中间位置,若手机内存再得不到释放,该应用程序有被系统杀死的风险
TRIM_MEMORY_COMPLETE 内存不足级别:80
状态:应用程序处于后台缓存
含义:内存严重不足,该应用程序已经处于LRU缓存列表的最边缘位置,应用程序随时有被回收的风险,此时应该把一切可以释放的资源都释放从而避免被杀死

合并Application

子Module和主Module最终会合成一份AndroidManifest(app\build\intermediates\manifests\full\debug\AndroidManifest.xml

合并规则:

  1. 子Module有自定义Application,主Module没有。子Module的Application合并到最终的AndroidManifest文件中
  2. 子Module无自定义Application,主Module有。主Module合并到最终AndroidManifest中。
  3. 多个子Module有自定义Application,在解决冲突后会在最终合并的AndroidManifest中使用最后编译的Module中的Application
  4. 子Module有自定义Application,主Module也有。会提示要在主Module的AndroidManifest中加tools:replace。最终AndroidManifest使用的是主Module中自定义的Application。

动态配置Application

除了Application需要合并之外,在组件化过程中各个Module的初始化可以通过在主Module中反射完成各个Module的初始化。如:

1
2
3
4
5
6
7
8
public class ModuleConfig{
private static final String MODULE_ONE_INIT = "com.example.module_one.ModuleOneAppInit";
private static final String MODULE_TWO_INIT = "com.example.module_two.ModuleTwoAppInit";
public static String[] moduleInits = {
MODULE_ONE_INIT,
MODULE_TWO_INIT
}
}

以下代码放在可被所有子Module依赖的库中

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 统一初始化接口
*/
public interface BaseAppInit{
/**
* 高优先级被初始化
*/
boolean onInitHighPriority(Application application);
/**
* 低优先级被初始化
*/
boolean onInitLowPriority(Application application);
}

子Module继承BaseAppInit实现自己Module的初始化工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* module_one的初始化文件
*/
public class ModuleOneAppInit implements BaseAppInit{
private static final String TAG = ModuleOneAppInit.class.getSimpleName();

@Override
public boolean onInitHighPriority(Application application) {
Log.i(TAG, "ModuleOneAppInit---onInitHighPriority");
return true;
}

@Override
public boolean onInitLowPriority(Application application) {
Log.i(TAG, "ModuleOneAppInit---onInitLowPriority");
return true;
}
}

在主Module的自定义Application中通过反射创建各个子Module的初始化类对象,并调用其初始化方法

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
27
28
29
/**
* 高优先级初始化
*/
private void initModuleHighPriority(){
for(String init: ModuleConfig.moduleInits){
try{
Class<?> clazz = Class.forName(init);
BaseAppInit appInit = (BaseAppInit) clazz.newInstance();
appInit.onInitHighPriority(this);
} catch(ClassNotFoundException | IllegalAccessException | InstantiationException e){
e.printStackTrace();
}
}
}

/**
* 低优先级初始化
*/
private void initModuleLowPriority(){
for(String init: ModuleConfig.moduleInits){
try{
Class<?> clazz = Class.forName(init);
BaseAppInit appInit = (BaseAppInit) clazz.newInstance();
appInit.onInitLowPriority(this);
} catch(ClassNotFoundException | IllegalAccessException | InstantiationException e){
e.printStackTrace();
}
}
}

另一种实现方式:创建基类BaseAppInit (给主Module和每个子Module的Application来继承);创建BaseApplication(给主Module继承)其中通过反射进行每个子Module的Application的初始化;最后在主Module中进行添加各个子Module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 在基类Module 中创建,管理各子 Module 的Application
*/
public abstract class BaseAppInit {
private Application mApplication;
public BaseAppInit() {}
public void setApplication(@NonNull Application application) {
this.mApplication = application;
}
public void onCreate(){}
public void OnTerminate(){}
public void onLowMemory(){}
public void configurationChanged(Configuration configuration){}
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* 在基类 Module 中创建
*/
public abstract class BaseApplication extends Application{
private List<Class<? extends BaseAppInit>> classInitList = new ArrayList<>();
private List<BaseAppInit> appInitList = new ArrayList<>();

@Override
public void onCreate(){
super.onCreate();
appInit();
initCreate();
}

protected abstract void appInit();
protected void registerApplicationInit(Class<? extends BaseAppInit> classInit){
classInitList.add(classInit);
}
private void initCreate(){
for(Class<? extends BaseAppInit> classInit : classInitList){
try{
BaseAppInit appInit = classInit.newInstance();
appInitList.add(appInit);
appInit.onCreate();
} catch (InstantiationException | IllegalAccessException e){
e.printStackTrace();
}
}
}

@Override
public void onTerminate(){
super.onTerminate();
for (BaseAppInit appInit : appInitList) {
appInit.OnTerminate();
}
}

@Override
public void onLowMemory() {
super.onLowMemory();
for (BaseAppInit appInit : appInitList) {
appInit.onLowMemory();
}
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
for (BaseAppInit appInit : appInitList) {
appInit.configurationChanged(newConfig);
}
}
}

在主 Module 中实现自定义 Application 并注册每个子 Module 的初始化文件

1
2
3
4
5
6
7
public class MApplication extends BbaseApplication{
@Override
protected void appInit(){
registerApplicationInit(ModuleThreeAppInit.class);
registerApplicationInit(ModuleForeAppInit.class);
}
}

在各个子 Module 中实现具体的初始化类

1
2
3
4
5
6
7
public class ModuleTreeAppInit extends BaseAppInit{
private static final String TAG = ModuleThreeAppInit.class.getSimpleName();
@Override
public void onCreate() {
Log.i(TAG, "ModuleThreeAppInit---onCreate");
}
}

注意点

宿主和组件有同名资源时

宿主取的是宿主的资源。但是跳转到组件时,组件的是同名资源,所以组件显示的还是宿主的资源内容,此时点击会报错。

需要把组件的资源名称改一下。最好是在组件的build.gradleandroid中添加resourcePrefix "gank_" //给 Module 内的资源名增加前缀, 避免资源名冲突

1
android {    resourcePrefix "gank_" //给 Module 内的资源名增加前缀, 避免资源名冲突}

加这个后,点开组件的资源文件的时候会报红色,但是不影响运行。但最好还是要改一下资源文件的名称(加前缀)

插件化

RePlugin

VirtualAPK

atlas

几种插件和方案对比

插件化需要解决的技术点:

  • 资源如何加载,资源冲突问题如何解决
  • 代码如何加载访问
  • 插件的管理后台包括的内容
  • 插件的增量更新问题
  • 加载插件中的so库

《Android插件化开发指南》

四大组件都需要插件化技术吗

  • 游戏类App,有一套自己的在线更新流程,很多用的是Lua之类的脚本。

  • 手机助手、手机卫士,这类App对Service、Receiver、ContentProvider的使用比较多。所以四大组件的插件化都必须实现。

  • 音乐类、视频类、直播类App,除了使用比较多的Activity,对Service和Receiver的依赖很强。

  • 电商类、社交类、新闻类、阅读类App,基本是Activity,其他三大组件使用不是很多,可以只考虑对Activity插件化的支持。

如果App中主要是Activity,那么选择静态代理that框架就够了

Android插件化技术的发展历史,基本上分为两大流派:静态代理和动态替换

(插件化不能上google play,要用RN替代)

双开和虚拟机

既然插件化会慢慢被RN所取代,那么插件化的未来是什么?答案是,虚拟机技术。

VirtualAppDroidPlugin

Android底层知识

AMS、AIDL、Binder、PMS、双亲委托、ClassLoader等

底层知识分两种:

  • 知道概念即可,比如Zygote,其实App开发人员是不需要了解Zygote的,知道有这么个东西是“孕育天地”的就够了,类似的还有SurfaceFlinger、WMS这些概念。
  • 需要知道内部原理,比如Binder,关于Binder的介绍铺天盖地,但对于App开发者,需要了解的是它的架构模型,只要有Client、Server以及ServiceManager就足够了。

四大组件的底层通信机制都是基于Binder的,我们需要知道每个组件中,分别是哪些类扮演了Binder Client,哪些类扮演了Binder Server。知道这些概念有助于App开发人员进行插件化编程。

Binder原理

Binder分为Client和Server两个进程

Client和Server是相对的。谁发消息谁就是Client,接收消息的就是Server

Binder的组成

Binder的组成.png

IPC:进程间通信;

ServiceManager:负责把每个Binder Server注册到一个容器中(ServiceManager比喻成电话局,记录着每个住宅的电话。张三(Binder Client)拨打给李四(Binder Server))

Binder的通信过程

图中的SM即为ServiceManager。我们看到,Client不可以直接调用Server的add方法,因为它们在不同的进程中,就需要Binder来帮忙了。

Binder的通信流程.png

  • 首先,Server在SM容器中注册
  • 其次,Client若要调用Server的add方法,就需要先获取Server对象,但SM不会把真正的Server对象返回给Client,会把Server的代理对象Proxy返回给Client。
  • 再次,Client调用Proxy的add方法,ServerManager会帮它去调用Server的add方法,并把结果返回给Client。

综上所述:

1)学习Binder是为了更好地理解AIDL,基于AIDL模型,进而了解四大组件的原理。

2)理解了Binder再看AMS和四大组件的关系,就像是Binder的两个进程Server和Client通信。

AIDL原理

AIDL是Binder的延伸。

Android的很多系统服务都是AIDL,比如剪贴板。

学习AIDL需要知道以下几个类:

  • IBinder
  • IInterface
  • Binder
  • Proxy
  • Stub

当我们自定义一个aidl文件时(比如MyAidl.aidl,里面有一个sum方法), Android Studio会帮我们生成一个类文件MyAidl.java,如图2-3所示。

AIDL中涉及的类图.png

我们把MyAidl.java中的三个类拆开,就一目了然了,如下所示:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
public interface MyAidl extends android.os.IInterface{
public int sum(int a, int b) throws android.osRemoteException;
}

public abstract class Stub extends android.osBinder implements jianqiang.com.hostapp.MyAidl{
private static final java.lang.String DESCRIPTOR = "jianqiang.com.hostapp.MyAidl";
static final int TRANSACTION_sum = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);

/**
* Construct the stub at attach it to the interface.
*/
public Stub(){
this.attachInterface(this, DESCRIPTOR);
}

/**
* Cast an IBinder object into an jianqiang.com.hostapp.MyAidl interface,
* generating a proxy if needed.
*/
public static jianqiang.com.hostapp.MyAidl asInterface(android.os.IBinder obj){
if((obj == null)){
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if(((iin != null) && (iin instanceof jianqiang.com.hostapp.MyAidl))){
return ((jianqiang.com.hostapp.MyAidl) iin);
}
return new jianqiang.com.hostapp.MyAidl.Stub.Proxy(obj);
}

@Override
public android.os.IBinder asBinder(){
return this;
}

@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{
switch(code){
case INTERFACE_TRANSACTION:{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_sum:{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.sum(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}

return super.onTransact(code, data, reply, flags);
}
}

class Proxy implements jianqiang.com.hostapp.MyAidl {
private android.os.IBinder mRemote;

Proxy(android.os.IBinder remote){
mRemote = remote;
}

@Override
public android.os.IBinder asBinder(){
return mRemote;
}

public java.lang.String getInterfaceDescriptor(){
return DESCRIPTOR;
}

@Override
public int sum(int a, int b) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try{
_data.writeInterfaceToke(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_sum, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}

生成的三个类都在一个文件里,避免当有多个AIDL类的时候,Stub和Proxy类重名的问题。

插件化

插件轮子对比

DLA ACDD DroidPlugin APF TPF
加载非独立插件 x 支持 x 支持 支持
四大组件 x 支持 x 支持 支持
Application x x x 支持 支持
Notification x x x 支持 支持
组件完整生命周期 x 支持 支持 支持 支持
Service动态注册 x 支持 支持 支持 支持
插件可独立进程 x x 支持 支持 支持
宿主能力与资源共享 x x x x 支持
支持本地网页组件 x x x x 支持
支持联调插件 x x x x 支持
支持第三方启动插件Activity x x x x 支持
支持第三方bind插件Service x x x x 支持
显示协议框架 x x x x 支持
随系统切换语言 x x x x 支持
Tos控件库 x x x x 支持

框架对比-small

DyLA DiLA ACDD DyAPK DPG APF Small
加载非独立插件 x x 支持 支持 x 支持 支持
加载.so插件 x x ! x x x 支持
Activity生命周期 支持 支持 支持 支持 x 支持 支持
Service动态注册 x x 支持 x x 支持 x
资源分包共享 x x ! ! x ! 支持
公共插件打包共享 x x x x x x 支持
支持AppCompat x x x x x x 支持
支持本地网页组件 x x x x x x 支持
支持联调插件 x x x x x x 支持