前言
每個應(yīng)用在啟動的時候都會初始化一個application類,我們可以在這個類中做一些初始化的操作,例如第三方sdk的初始化,在實施組件化工程后,不同的業(yè)務(wù)模塊也需要在應(yīng)用啟動的時候做一些初始化的操作,這個就涉及到了模塊的生命周期問題,在應(yīng)用啟動時候,各個模塊可以拿到application,在Application內(nèi)部的生命周期方法被調(diào)用的時候,各個模塊也有相應(yīng)的生命周期方法被調(diào)用
初步實現(xiàn)
1.抽取一個IModuleLifeCycle類
代碼如下
public interface IModuleLifeCycle {
int MAX_PRIORITY = 12;
int MIN_PRIORITY = 1;
int DEFAULT_PRIORITY = 6;
void onCreate(Application application);
void onTerminate();
/**
* 返回組件的優(yōu)先級,優(yōu)先級范圍為[1-12],12為最高,1為最低,默認(rèn)優(yōu)先級是1
* @return
*/
int getPriority();
}
2.實現(xiàn)IModuleLifeCycle類
各個模塊內(nèi)新建一個類實現(xiàn)IModuleLifeCycle類,我們把這個當(dāng)作模塊的application類,在這個類可以做一些初始化的操作,還可以獲取application對象,做一些初始化全局變量的工作
3.如何管理組件的生命周期
假如現(xiàn)在有moduleA, moduleB, moduleC,然后這三個模塊分別對應(yīng)有ModuleALifeCycle,ModuleBLifeCycle,ModuleCLifeCycle實現(xiàn)了IModuleLifeCycle類,用于實現(xiàn)模塊的生命周期,為了實現(xiàn)這三個模塊的生命周期,簡單的做法是在application類中獲取這個三個類的實例,然后在application的onCreate方法中調(diào)用ModuleALifeCycle,ModuleBLifeCycle,ModuleCLifeCycle的onCreate方法,代碼如下:
@Override
public void onCreate() {
super.onCreate();
IModuleLifeCycle moduleA = new ModuleALifeCycle();
IModuleLifeCycle moduleB = new ModuleBLifeCycle();
IModuleLifeCycle moduleC = new ModuleCLifeCycle();
moduleA.onCreate(this);
moduleB.onCreate(this);
moduleC.onCreate(this);
}
這種方式很簡單,有多少個模塊,就初始化多少個模塊生命周期類,然后調(diào)用onCreate()即可,但是這種做法是不利于維護(hù)的,每次新加一個模塊,就需要新建一個模塊類,然后在application中調(diào)用這個類。而且,在模塊化的開發(fā)模式下,各個模塊獨立運行的時候,殼工程對各個模塊是沒有依賴的,這就會導(dǎo)致上面的代碼編譯報錯,所以是非常不可取的,因此,有兩種方法可以優(yōu)化:
1.在配置文件中定義各個模塊生命周期類的路徑, 在assets中配置一個json文件,其中定義著各個模塊的生命周期類的路徑,然后在application初始化的時候通過反射獲取這些類,然后調(diào)用其中生命周期方法,從而完成模塊的生命周期的初始化,但是這種方法還是不夠靈活,因為需要維護(hù)配置文件,所以更好的方法是連配置文件都不需要維護(hù)
2.使用APT+javaPoet的方式實現(xiàn),給模塊生命周期類添加注解,然后使用APT掃描特定注解,然后借助javaPoet生成生命周期代理類,放在特定的目錄下,這些代理類擁有模塊生命周期類的實例,每次application初始化的時候,就會掃描dex下面特定路徑的類,獲得這些類的路徑,然后通過反射獲取類的實例,這些類就是javaPoet生成的代理類,我們會調(diào)用這些代理類的內(nèi)部方法,從而調(diào)用到模塊生命周期類的方法,完成各個模塊生命周期的初始化
最終實現(xiàn)
使用APT+javaPoet的方式實現(xiàn)
1. 實現(xiàn)思路
- 在工程中新建一個類實現(xiàn)IModuleLifeCycle類,并且添加特定的注解,代碼如下
@ModuleLifeCycle(moduleName = "main", desc = "主模塊")
public class MainLifeCycle implements IModuleLifeCycle {
@Override
public void onCreate(Application application) {
//.. 初始化主工程的Application的時候會調(diào)用到這里
//.. application是整個應(yīng)用的application
// ..在這里完成自身module的初始化
System.out.println("====>onCreate:"+application);
}
@Override
public void onTerminate() {
//.. Application被銷毀
}
@Override
public int getPriority() {
return DEFAULT_PRIORITY;
}
}
- APT在編譯的時候會掃描這個特定的注解,然后利用javaPoet生成模塊生命周期的代理類,放在特定的路徑下,代理類代碼如下:
public class MainLifeCycleProxy implements IModuleLifeCycle {
public MainLifeCycle mModuleLifeCycle;
public MainLifeCycleProxy() {
mModuleLifeCycle = new MainLifeCycle();
}
@Override
public void onCreate(Application application) {
mModuleLifeCycle.onCreate(application);
}
@Override
public int getPriority() {
return mModuleLifeCycle.getPriority();
}
@Override
public void onTerminate() {
mModuleLifeCycle.onTerminate();
}
}
- application在初始化的時候可以掃描dex下特定路徑下的類,獲取類的路徑,然后通過反射獲取代理類實例, 調(diào)用
代理類的onCreate方法,從而調(diào)用到各個模塊的生命周期類的onCreate方法,實現(xiàn)模塊生命周期,掃描代碼如下所示:
/**
* 通過指定包名,掃描包下面包含的所有的ClassName
*
* @param context U know
* @param packageName 包名
* @return 所有class的集合
*/
public static Set<String> getFileNameByPackageName(Context context, final String packageName) throws PackageManager.NameNotFoundException, IOException, InterruptedException {
final Set<String> classNames = new HashSet<>();
List<String> paths = getSourcePaths(context);
final CountDownLatch parserCtl = new CountDownLatch(paths.size());
for (final String path : paths) {
DefaultPoolExecutor.getInstance().execute(new Runnable() {
@Override
public void run() {
DexFile dexfile = null;
try {
if (path.endsWith(EXTRACTED_SUFFIX)) {
//NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache"
dexfile = DexFile.loadDex(path, path + ".tmp", 0);
} else {
dexfile = new DexFile(path);
}
Enumeration<String> dexEntries = dexfile.entries();
while (dexEntries.hasMoreElements()) {
String className = dexEntries.nextElement();
if (className.startsWith(packageName)) {
classNames.add(className);
}
}
} catch (Throwable ignore) {
Log.e("ARouter", "Scan map file in dex files made error.", ignore);
} finally {
if (null != dexfile) {
try {
dexfile.close();
} catch (Throwable ignore) {
}
}
parserCtl.countDown();
}
}
});
}
parserCtl.await();
return classNames;
}
2. 實現(xiàn)過程
1. 定義注解
在androidStudio中新建一個Java Library module,然后新建一個注解類,命名為ModuleLifeCycle,工程結(jié)構(gòu)如下所示:
[圖片上傳失敗...(image-524d0c-1636621603045)]
ModuleLifeCycle代碼如下所示,
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface ModuleLifeCycle {
String moduleName();
String desc();
}
2. 新建一個android module lib,命名為module-lifecycle-api,工程結(jié)構(gòu)如下所示:
[圖片上傳失敗...(image-1e40d4-1636621603045)]
IModuleLifeCycle是模塊生命周期的接口,代碼如下:
public interface IModuleLifeCycle {
int MAX_PRIORITY = 12;
int MIN_PRIORITY = 1;
int DEFAULT_PRIORITY = 6;
void onCreate(Application application);
void onTerminate();
/**
* 返回組件的優(yōu)先級,優(yōu)先級范圍為[1-10],10為最高,1為最低,默認(rèn)優(yōu)先級是5
* @return
*/
int getPriority();
}
其中g(shù)etPriority()方法表示模塊加載的優(yōu)先級,在多模塊工程中,優(yōu)先級越高的模塊,越先初始化生命周期,
ModuleLifeCycleManager是生命周期的管理類,用于按照優(yōu)先級初始化各個模塊
3.新建一個 java lib module,命名為module-lifecycle-apt,代碼結(jié)構(gòu)如下
[圖片上傳失敗...(image-ad0c2-1636621603045)]
在這個模塊中,我們將使用apt掃描注解,并且用javaPoet生成代理類,module-lifecycle-apt庫的build.gradle
配置代碼如下:
plugins {
id 'java-library'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
//這是谷歌提供的一個自動服務(wù)注冊框架,需要用到
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7'
compileOnly 'com.google.auto.service:auto-service-annotations:1.0-rc7'
implementation 'com.squareup:javapoet:1.10.0'
implementation project(':module-lifeCycle-annotation')
}
java {
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
ModuleLifeCycleProcessor調(diào)用了apt的api來掃描特定注解,代碼如下:
@AutoService(Processor.class)
public class ModuleLifeCycleProcessor extends AbstractProcessor {
public Filer filer; //文件相關(guān)的輔助類
public Elements elements; //元素相關(guān)的輔助類
public Messager messager; //日志相關(guān)的輔助類
private Map<String, CodeCreateFactory> codeCreateFactoryMap = new HashMap<>();
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnv.getFiler();
elements = processingEnv.getElementUtils();
messager = processingEnv.getMessager();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> set = new LinkedHashSet<>();
set.add(ModuleLifeCycle.class.getCanonicalName());
return set;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();//改成這個后process方法會進(jìn)來兩次,查一下去為什么
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
Set<? extends Element> elementSet = roundEnvironment.getElementsAnnotatedWith(ModuleLifeCycle.class);
for (Element element : elementSet) {
if (!element.getKind().isClass()) {
throw new RuntimeException("ModuleLifeCycle注解只能用在類上");
}
TypeElement typeElement = (TypeElement) element;
if (codeCreateFactoryMap.containsKey(typeElement.getSimpleName().toString())) {
codeCreateFactoryMap.get(typeElement.getSimpleName().toString()).generateCode();
} else {
CodeCreateFactory codeCreateFactory = new CodeCreateFactory(typeElement, processingEnv);
codeCreateFactoryMap.put(typeElement.getSimpleName().toString(), codeCreateFactory);
codeCreateFactory.generateCode();
}
}
return true;
}
}
CodeCreateFactory調(diào)用了javaPoet的api來生成指定的代碼,并且保存到特定路徑下,代碼如下:
public class CodeCreateFactory {
TypeElement typeElement;
ProcessingEnvironment processingEnv;
public CodeCreateFactory(TypeElement typeElement, ProcessingEnvironment processingEnv) {
this.typeElement = typeElement;
this.processingEnv = processingEnv;
}
public void generateCode() {
TypeSpec ModuleFeedLifeCycleManger = TypeSpec
.classBuilder(typeElement.getSimpleName().toString() + "Proxy")
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(ClassName.get("com.quwan.moduleLifecycleApi", "IModuleLifeCycle"))
.addField(FieldSpec
.builder(ClassName.get(typeElement.getQualifiedName().toString().replace("." + typeElement.getSimpleName().toString(), ""),
typeElement.getSimpleName().toString()), "mModuleLifeCycle", Modifier.PUBLIC)
.build())
.addMethod(MethodSpec
.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addStatement("mModuleLifeCycle = new $T()", ClassName.get(typeElement.getQualifiedName().toString().replace("." + typeElement.getSimpleName().toString(), ""),
typeElement.getSimpleName().toString()))
.build())
.addMethod(MethodSpec
.methodBuilder("onCreate")
.addAnnotation(ClassName.get("java.lang", "Override"))
.addModifiers(Modifier.PUBLIC)
.addParameter(
ParameterSpec
.builder(ClassName.get("android.app", "Application"), "application")
.build()
)
.addStatement("mModuleLifeCycle.onCreate(application)")
.build())
.addMethod(MethodSpec
.methodBuilder("getPriority")
.returns(INT)
.addAnnotation(ClassName.get("java.lang", "Override"))
.addModifiers(Modifier.PUBLIC)
.addStatement("return mModuleLifeCycle.getPriority()")
.build())
.addMethod(MethodSpec
.methodBuilder("onTerminate")
.returns(VOID)
.addAnnotation(ClassName.get("java.lang", "Override"))
.addModifiers(Modifier.PUBLIC)
.addStatement("mModuleLifeCycle.onTerminate()")
.build())
.build();
JavaFile javaFile = JavaFile.builder("com.component.lifeCycle", ModuleFeedLifeCycleManger).build();
try {
// 生成文件
javaFile.writeTo(processingEnv.getFiler());
} catch (IOException e) {
e.printStackTrace();
}
}
}
以上就完成了實現(xiàn)過程,其實還是挺簡單的
3. 如何使用
1. 在application的onCreate()方法中調(diào)用ModuleLifeCycleManager的方法,代碼如下:
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
ModuleLifeCycleManager.init(this);
}
@Override
public void onTerminate() {
super.onTerminate();
ModuleLifeCycleManager.terminate();
}
}
2. 在模塊中新建一個生命周期類,實現(xiàn)IModuleLifeCycle接口,并且添加注解,代碼如下
@ModuleLifeCycle(moduleName = "main", desc = "主模塊")
public class MainLifeCycle implements IModuleLifeCycle {
@Override
public void onCreate(Application application) {
//.. 初始化主工程的Application的時候會調(diào)用到這里
//.. application是整個應(yīng)用的application
// ..在這里完成自身module的初始化
System.out.println("====>onCreate:"+application);
}
@Override
public void onTerminate() {
//.. Application被銷毀
}
@Override
public int getPriority() {
return DEFAULT_PRIORITY;
}
}
3. rebuild一下工程,生成模塊生命周期代理類,代碼如下:
package com.component.lifeCycle;
import android.app.Application;
import com.quwan.moduleLifecycleApi.IModuleLifeCycle;
import com.quwan.modulelifecycle.MainLifeCycle;
import java.lang.Override;
public class MainLifeCycleProxy implements IModuleLifeCycle {
public MainLifeCycle mModuleLifeCycle;
public MainLifeCycleProxy() {
mModuleLifeCycle = new MainLifeCycle();
}
@Override
public void onCreate(Application application) {
mModuleLifeCycle.onCreate(application);
}
@Override
public int getPriority() {
return mModuleLifeCycle.getPriority();
}
@Override
public void onTerminate() {
mModuleLifeCycle.onTerminate();
}
}
以上就完成了模塊生命周期的初始化過程了