組件化之如何實現(xiàn)模塊生命周期自動管理

前言

每個應(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)思路

  1. 在工程中新建一個類實現(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;
    }
}
  1. 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();
  }
}
  1. 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();
  }
}

以上就完成了模塊生命周期的初始化過程了

github鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容