可参照项目《Android 组件化实战》
原来一个项目只需要实现一个 Application 的实例,完成应用中所有需要初始化的操作,并且在 AndroidManifest.xml 文件 中注册一次就可以。
组件化以后,由于各个模块单独可实现编译,所以各个组件需要注册自己的 Application 实例,并且在自己的 Application 实现类中完成自己需要的初始化业务。并且在很多时候某个组件可能在单独编译的时候会初始化一些业务,在合并编译的时候并不需要。这个时候就希望 app 主 module 能够灵活的管理到各个组件的生命周期,在不同情况下调用到相应的初始化业务,并且保证组件的独立和解耦。
本文采用的一种处理方式是,将各个 module 都必须要进行初始化的部分业务,通过定义接口抽象出来,各个组件进行具体的实现子类,去剥离组件化状态下单独编译时和合并编译时的各组件生命周期的不同处理逻辑,这样也解耦了部分初始化的业务,也有利于此处功能的扩展。
首先通过 UML 图例了解其中部分各相关类的关系,然后再分析具体的功能实现;
抽象一个与 application 各生命周期方法匹配的接口:
package com.windfallsheng.componentbasedaction.module_base.command;
import android.content.res.Configuration;
/**
* @Author: lzsheng
*/
public interface IApplicationHelper {
void onCreate();
void onTerminate();
void onLowMemory();
void onConfigurationChanged(Configuration configuration);
}
实现一个抽象基类 BaseApplicationHelper ,空实现一些方法,避免实现类都得实现所有不必要的方法。
package com.windfallsheng.componentbasedaction.module_base.command;
import android.app.Application;
import android.content.res.Configuration;
/**
* @Author: lzsheng
*/
public abstract class BaseApplicationHelper implements IApplicationHelper {
protected Application mApplication;
public BaseApplicationHelper(Application application) {
this.mApplication = application;
}
@Override
public void onTerminate() {
}
@Override
public void onLowMemory() {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
}
}
main 组件实现子类, 在 onCreate 方法里进行必须的初始化业务
package com.windfallsheng.componentbasedaction.module_main.command;
import android.app.Application;
import com.windfallsheng.componentbasedaction.component_lib.util.Logger;
import com.windfallsheng.componentbasedaction.module_base.command.BaseApplicationHelper;
/**
* @Author: lzsheng
*/
public class MainApplicationHelper extends BaseApplicationHelper {
private final String TAG = "MainApplicationHelper";
public MainApplicationHelper(Application application) {
super(application);
}
@Override
public void onCreate() {
Logger.dl("method:onCreate#不同的模式下当前组件必须的初始化业务");
}
}
login 组件实现子类, 在 onCreate 方法里进行必须的初始化业务
package com.windfallsheng.componentbasedaction.module_login.command;
import android.app.Application;
import com.windfallsheng.componentbasedaction.component_lib.util.Logger;
import com.windfallsheng.componentbasedaction.module_base.command.BaseApplicationHelper;
/**
* @Author: lzsheng
*/
public class LoginApplicationHelper extends BaseApplicationHelper {
private final String TAG = "LoginApplicationHelper";
public LoginApplicationHelper(Application application) {
super(application);
}
@Override
public void onCreate() {
Logger.dl(TAG, "method:onCreate#不同的模式下当前组件必须的初始化业务");
}
}
pay 组件实现子类, 在 onCreate 方法里进行必须的初始化业务
package com.windfallsheng.componentbasedaction.module_pay.command;
import android.app.Application;
import com.windfallsheng.componentbasedaction.component_lib.util.Logger;
import com.windfallsheng.componentbasedaction.module_base.command.BaseApplicationHelper;
/**
* @Author: lzsheng
*/
public class PayApplicationHelper extends BaseApplicationHelper {
private final String TAG = "PayApplicationHelper";
public PayApplicationHelper(Application application) {
super(application);
}
@Override
public void onCreate() {
Logger.dl(TAG, "method:onCreate#不同的模式下当前组件必须的初始化业务");
}
}
抽象的 BaseApplication 基类,主要进行三项业务:
1、在基类中初始化一次各module通用的功能。
2、针对各个Module自身特有的业务,在分开打包时,各个module可以重写 initComponentSpecificService 方法,进行初始化业务;
3、根据注入的各个Module 的 ApplicationHelper 实现类,调用相应的方法,进行各 Module 的初始化业务;
对其它各组件的 ApplicationHelper 的实例创建是通过 全路径名 反射来实现。
package com.windfallsheng.componentbasedaction.module_base.command;
import android.app.Application;
import android.content.res.Configuration;
import androidx.multidex.MultiDexApplication;
import com.alibaba.android.arouter.launcher.ARouter;
import com.windfallsheng.componentbasedaction.component_lib.util.Logger;
import com.windfallsheng.componentbasedaction.module_base.BuildConfig;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: lzsheng
*/
public abstract class BaseApplication extends MultiDexApplication {
private static Application mApplication;
private final String TAG = "BaseApplication";
private boolean mDebug;
/**
* 各个Module中针对各个Module自身特有的初始化业务;
*/
private List<IApplicationHelper> mApplicationHelperList = new ArrayList<>();
public static Application getInstance() {
return mApplication;
}
@Override
public void onCreate() {
super.onCreate();
mApplication = this;
this.mDebug = BuildConfig.DEBUG;
// 在基类中初始化一次各module通用的功能,
initComponentCommonService();
Logger.dl("method:onCreate#mApplication=" + mApplication.getClass().getName());
// 针对各个Module自身特有的业务,在分开打包时,各个module可以重写些方法,进行初始化业务;
initComponentSpecificService();
// 各个Module必须要进行的初始化业务;
handlelAllApplicationHelpersCreate();
}
/**
* 初始化各个module通用的业务;
*/
private void initComponentCommonService() {
Logger.initDebug(mDebug);
Logger.dl("method:initComponentCommonService#初始化各个组件公共的业务");
// ARouter初始化相关
if (mDebug) {
//打印日志
ARouter.openLog();
//开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
ARouter.openDebug();
}
ARouter.init(mApplication);
}
/**
* 对于各个module在单独编译时,如果有必要的业务需要处理则重写此方法;
*/
protected void initComponentSpecificService() {
Logger.dl("method:initComponentSpecificService#初始化各个组件自身特有的业务#" + TAG + "里定义的空实现");
}
/**
* 处理注册初始化功能的业务实例,及调用各实例的onCreate()方法;
*/
private void handlelAllApplicationHelpersCreate() {
Logger.dl("method:handlelAllApplicationHelpersCreate");
// 首先注册具体实例;
registeApplicationHelper();
// 调用各实例的初始化方法
mApplicationHelperList.stream()
.forEach(applicationHelper -> {
Logger.d("method:handlelAllApplicationHelpersCreate#applicationHelper=" +
applicationHelper.getClass().getSimpleName());
applicationHelper.onCreate();
});
}
/**
* 注册各个Module中用于初始化功能的业务实例;
*/
protected abstract void registeApplicationHelper();
/**
* 根据全路径名,通过反射注册相关实例;各组件单独编译时,其它组件会报异常
*
* @param className
*/
protected void registerTargetApplicationHelper(String className) {
BaseApplicationHelper applicationHelper = null;
try {
Class<? extends BaseApplicationHelper> clazz = (Class<? extends BaseApplicationHelper>) Class.forName(className);
Constructor<? extends BaseApplicationHelper> constructor = clazz.getConstructor(Application.class);
applicationHelper = constructor.newInstance(BaseApplication.this);
} catch (IllegalAccessException | InstantiationException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
Logger.el("method:registerApplicationHelper#e=" + e.getMessage());
}
if (applicationHelper != null) {
mApplicationHelperList.add(applicationHelper);
}
}
/**
* 根据全路径名的数组,通过反射注册相关实例;各组件单独编译时,其它组件会报异常
*
* @param classNameArray
*/
protected void registerApplicationHelperArray(String[] classNameArray) {
for (String className : classNameArray) {
BaseApplicationHelper applicationHelper = null;
try {
Class<? extends BaseApplicationHelper> clazz = (Class<? extends BaseApplicationHelper>) Class.forName(className);
Constructor<? extends BaseApplicationHelper> constructor = clazz.getConstructor(Application.class);
applicationHelper = constructor.newInstance(BaseApplication.this);
} catch (IllegalAccessException | InstantiationException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
Logger.el("method:registerapplicationHelperArray#e=" + e.getMessage());
}
if (applicationHelper != null) {
mApplicationHelperList.add(applicationHelper);
}
}
}
@Override
public void onTerminate() {
super.onTerminate();
mApplicationHelperList.stream()
.forEach(applicationHelper ->
applicationHelper.onTerminate());
}
@Override
public void onLowMemory() {
super.onLowMemory();
mApplicationHelperList.stream()
.forEach(applicationHelper ->
applicationHelper.onLowMemory());
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mApplicationHelperList.stream()
.forEach(applicationHelper ->
applicationHelper.onConfigurationChanged(newConfig));
}
}
MyApplication 作为主项目中注册的 application 实例,是合并编译的时候会被初始化,所以会管理并注册所有 Module 的初始化ApplicationHelper 实例。
这时会加入所有组件的ApplicationHelper 的全路径名,会通过反射创建相应对象,然后实现对其它各组件的 ApplicationHelper 的功能调用。
package com.windfallsheng.componentbasedaction.command;
import com.windfallsheng.componentbasedaction.component_lib.util.Logger;
import com.windfallsheng.componentbasedaction.module_base.BaseConsts;
import com.windfallsheng.componentbasedaction.module_base.command.BaseApplication;
/**
* @Author: lzsheng
*/
public class MyApplication extends BaseApplication {
private static final String TAG = "MyApplication";
/**
* 增加新的组件时,需要在此数组中添加相应的数据,保证模块上下文及其相关初始化成功;
*/
private static final String[] APPLICATION_HELPER_NAME_LIST =
{
// MyApplicationHelper.class.getName(),
BaseConsts.ApplicationHelperClassName.MAIN_APPLICATION_HELPER,
BaseConsts.ApplicationHelperClassName.LOGIN_APPLICATION_HELPER,
BaseConsts.ApplicationHelperClassName.PAY_APPLICATION_HELPER
};
@Override
protected void registeApplicationHelper() {
Logger.dl(TAG, "method:registeApplicationHelper#项目合并编译时,注册所有相关初始化业务类");
registerApplicationHelperArray(APPLICATION_HELPER_NAME_LIST);
}
}
Main 组件单独编译时的 MainApplication 处理逻辑,只需要注册自己的 applicationHelper;使得自身的初始化业务完整即可。
package com.windfallsheng.componentbasedaction.module_main.command;
import com.windfallsheng.componentbasedaction.component_lib.util.Logger;
import com.windfallsheng.componentbasedaction.module_base.command.BaseApplication;
/**
* @Author: lzsheng
*/
public class MainApplication extends BaseApplication {
private final String TAG = "MainApplication";
@Override
protected void initComponentSpecificService() {
Logger.dl("method:initComponetSpecificService#单独编译时,初始化当前组件特有的业务");
}
@Override
protected void registeApplicationHelper() {
Logger.dl(TAG, "method:registeApplicationHelper#单独编译时,注册相关初始化业务类");
registerTargetApplicationHelper(MainApplicationHelper.class.getName());
}
}
login 组件单独编译时的 MainApplication 处理逻辑,只需要注册自己的 applicationHelper;使得自身的初始化业务完整即可。
package com.windfallsheng.componentbasedaction.module_login.command;
import com.windfallsheng.componentbasedaction.component_lib.util.Logger;
import com.windfallsheng.componentbasedaction.module_base.command.BaseApplication;
/**
* @Author: lzsheng
*/
public class LoginApplication extends BaseApplication {
private final String TAG = "LoginApplication";
@Override
protected void initComponentSpecificService() {
Logger.dl(TAG, "method:initComponetSpecificService#单独编译时,初始化当前组件特有的业务");
}
@Override
protected void registeApplicationHelper() {
Logger.dl(TAG, "method:registeApplicationHelper#单独编译时,注册相关初始化业务类");
registerTargetApplicationHelper(LoginApplicationHelper.class.getName());
}
}
假如 pay 组件需要在单独编译的时候,希望 login 组件作为普通 module ,去添加依赖,这时候 PayApplication 可以这样处理:
package com.windfallsheng.componentbasedaction.module_pay.command;
import com.windfallsheng.componentbasedaction.component_lib.util.Logger;
import com.windfallsheng.componentbasedaction.module_base.BaseConsts;
import com.windfallsheng.componentbasedaction.module_base.command.BaseApplication;
/**
* @Author: lzsheng
*/
public class PayApplication extends BaseApplication {
private final String TAG = "PayApplication";
/**
* 当支付模块单独编译时,由于它需要依赖登录模块,需要在此数组中添加相应的数据,保证模块上下文及其相关初始化成功;
*/
private static final String[] APPLICATION_HELPER_NAME_LIST =
{
PayApplicationHelper.class.getName(),
BaseConsts.ApplicationHelperClassName.LOGIN_APPLICATION_HELPER
};
@Override
protected void initComponentSpecificService() {
Logger.dl(TAG, "method:initComponentSpecificService#单独编译时,初始化当前组件特有的业务");
}
@Override
protected void registeApplicationHelper() {
Logger.dl(TAG, "method:registeApplicationHelper#单独编译时,注册相关初始化业务类");
// registerApplicationHelper(PayApplicationHelper.class.getName());
registerApplicationHelperArray(APPLICATION_HELPER_NAME_LIST);
}
}
相关的 AndroidManifest 配置情况:
主项目 app 壳模块中AndroidManifest 的配置文件中注册 MyApplication:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.windfallsheng.componentbasedaction">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:name=".command.MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ComponentBasedAction"></application>
</manifest>
其它组件中的配置:
pay 组件单独编译情况下AndroidManifest 的配置中注册自己的 PayApplication:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.windfallsheng.componentbasedaction.module_pay">
<application
android:name=".command.PayApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher_foreground"
android:label="@string/template_app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ComponentBasedAction"
tools:replace="android:label">
<activity android:name="module.PayMainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".views.PayActivity" />
</application>
</manifest>
合并编译时AndroidManifest 不需要多余的配置项:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.windfallsheng.componentbasedaction.module_pay">
<application>
<activity android:name=".views.PayActivity" />
</application>
</manifest>
定义所有相关类的全路径字符串变量:
package com.windfallsheng.componentbasedaction.module_base;
public class BaseConsts {
/**
* 定义所有相关类的全路径字符串变量;
* <p>
* 增加新的组件时,需要在此数组中添加相应的数据;
*/
public static class ApplicationHelperClassName {
public static final String PREFIX = "com.windfallsheng.componentbasedaction.";
/**
* 必须是类的全路径名
*/
public static final String MAIN_APPLICATION_HELPER =
PREFIX + "module_main.command.MainApplicationHelper";
public static final String LOGIN_APPLICATION_HELPER =
PREFIX + "module_login.command.LoginApplicationHelper";
public static final String PAY_APPLICATION_HELPER =
PREFIX + "module_pay.command.PayApplicationHelper";
}
}
以上只是一种实现方法,可以根据项目的自身情况,用其它的方式处理。