Android组件生命周期管理 - Go语言中文社区

Android组件生命周期管理


每个Android应用启动时,都会先创建一个Application。通常在Application里我们会做一些应用初始化的操作,常见的有第三方SDK初始化。在应用组件化之后,组件与壳工程是隔离开来的,但是组件有时候也需要获取应用的Application,也需要在应用启动时进行初始化。这就涉及到组件的生命周期管理问题。

最简单的实现方式如下:

  1. 我们定义一个Application的代理接口IAppLike出来,它模拟了Application的几个主要方法。
public interface IAppLike {      
    void onCreate();     
    void onTerminate();     
    void onLowMemory();    
    void onTrimMemory(int level);  
}
  1. 在组件内部写一个实现IAppLike的类,我们把这个类当做是组件的Application容器。这里的onCreate()等同于Application的onCreate()方法,组件可以在这里获取Application实例、执行启动初始化等操作,也可以在这里设置保存一些全局性的数据等。
public class NewsDelegate implements IApplicationDelegate {
    @Override
    public void onCreate() {
        Log.i("hx", "NewsDelegate-onCreate");
    }

    @Override
    public void onTerminate() {
        Log.i("hx", "NewsDelegate-onTerminate");
    }

    @Override
    public void onLowMemory() {
    }

    @Override
    public void onTrimMemory(int level) {
    }
}
  1. 在壳工程的Application.onCreate()方法里执行:
@Override 
public void onCreate() {     
   super.onCreate();     
   MainDelegate mainDelegate = new MainDelegate();     
   NewsDelegate newsDelegate = new NewsDelegate();     
   MusicDelegate musicDelegate = new MusicDelegate();     
   MimeDelegate mimeDelegate = new MimeDelegate(); 
   mainDelegate.onCreate();     
   newsDelegate.onCreate();     
   musicDelegate.onCreate();     
   mimeDelegate.onCreate();     
}

看起来貌似很简单,根本没什么技术含量,但是实际运用时,你会发现很多问题:
(1)组件初始化先后顺序问题:
前面介绍过,上层业务组件是依赖下层业务组件的,如果下层组件在应用启动时也需要初始化,那么我们在加载组件时,必然要先加载下层组件,否则加载上层组件时可能会出现问题。但是组件这么多,我们怎么确定要先加载谁后加载谁呢,当然你可以手动维护,代码里写死,但是当业务越来越多、时间越来越久,肯定不灵活,你新加一个业务组件进来,你都需要确定组件初始化先后顺序。所以,我们必须有个机制来确定组件初始化先后顺序。
类似线程优先级一样, 为每个组件定义了一个优先级,通过重写getPriority()方法可以设置组件的优先级。优先级范围从[1-10],默认优先级都为5,下层组件或需要先初始化的组件,优先级设置高一点。这样我们在加载组件的时候,先对所有组件的优先级进行排序,优先级高的排前面,然后再按顺序进行加载组件,就可解决这个问题了。

(2)自动加载问题
这里需要在壳工程代码里,手动构建各个组件的Delegate类。如果很多个组件都有实现该类,那在集成时得一个一个找出这些类,并且新增加一个组件,你都有可能要去修改壳工程代码,这样显然是不灵活且不利于代码维护的。如果能自动读取并加载这些Delegate类,那显然是极好的,这里有2种方式来实现:

  • 全局扫描代理类

应用启动时通过包名全局扫描源代码文件并找到代理类,通过反射去加载并初始化组件。这种方式只需要在组件中实现代理类即可,实现起来比较简单,但是全局扫描有性能的损耗。

  • 自定义gradle插件/字节码插入技术

通过自定义gradle插件和字节码插入技术来实现AOP,在编译期间在BaseApplication生命周期中动态注入字节码,实现调用代理类的对应方法。

全局扫描代理类

在BaseApplication初始化时扫描出所有组件的代理类,再通过反射加载并初始化。这里也有个问题,所有组件的代理类散落在各个不同的组件中,包名各不相同,当扫描到class文件后判断条件就必须是【class文件全类命.equal(组件1代理类全类命) || class文件全类命.equal(组件2代理类全类命) || …】,是不是很麻烦,这里我们可以采取apt技术,通过编译时注解动态生成这些代理类的辅助文件,在辅助文件中调用代理类的方法,而这些辅助文件的包名一样,这样我们只需要扫描辅助文件就可以了,判断条件就变成【class文件包名.startWith(辅助文件包名)】,是不是简单多了。

初步思路:

  1. 定义一个注解来标识实现了IAppLike的类。
  2. 通过APT技术,在组件编译时扫描和处理前面定义的注解,生成一个AppLike的代理类,姑且称之为AppLikeProxy,所有的代理类都在同一个包名下,这个包名下必须只包含代理类,且类名由固定的规则来生成,保证不同组件生成的代理类的类名不会重复。
  3. 需要有一个组件生命周期管理类,初始化时能扫描到固定包名下有多少个类文件,以及类文件的名称,这个固定包名就是前面我们生成的AppLikeProxy的包名,代理类都放在同一个包名下,是为了通过包名找到我们所有的目标类。
  4. 组件集成后在应用的Application.onCreate()方法里,调用组件生命周期管理类的初始化方法。
  5. 组件生命周期管理类的内部,扫描到所有的AppLikeProxy类名之后,通过反射进行类实例化。

初步技术难点:
需要了解APT技术,怎么在编译时动态生成java代码;关于编译时注解可以参考
详解Android注解 Annotation这篇文章。
应用在运行时,怎么能扫描到某个包名下有多少个class,以及他们的名称呢;

注解定义

在Android Studio中,新建一个Java Library module,命名为lifecycle-annotation,在该module中创建一个注解类,同时创建一个后面要生成代理类的相关配置文件。
注解类:

@Retention(RetentionPolicy.CLASS) 
@Target(ElementType.TYPE) 
public @interface AppLifeCycle { }

配置文件:

public class LifeCycleConfig {      
/*** 生成代理类的包名      */     
public static final String PROXY_CLASS_PACKAGE_NAME = "com.example.lifecycle.apt.proxy";      
/*** 生成代理类统一的后缀      */     
public static final String PROXY_CLASS_SUFFIX = "$$Proxy";      
/*** 生成代理类统一的前缀      */     
public static final String PROXY_CLASS_PREFIX = "Watson$$";  }

使用APT来生成IAppLike的代理类

新建一个Java Library module,命名为lifecycle-apt,在该module里实现我们自己的注解处理器。

在build.gradle里修改配置为:

apply plugin: 'java-library'  

dependencies {     
implementation fileTree(dir: 'libs', include: ['*.jar'])      
implementation 'com.google.auto.service:auto-service:1.0-rc2'     
implementation project(':lifecycle-annotation')  
}  

sourceCompatibility = "1.8" 
targetCompatibility = "1.8"  

tasks.withType(JavaCompile) {     
   options.encoding = "UTF-8" 
}

接下来就是实现我们自己的注解处理器了:

@AutoService(Processor.class)
public class AppLikeProcessor extends AbstractProcessor {
    private Elements mElementUtils;
    private Map<String, AppLikeProxyClassCreator> mMap = new HashMap<>();

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        mElementUtils = processingEnvironment.getElementUtils();
    }

    /*** 支持解析的注解      */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> set = new LinkedHashSet<>();
        set.add(AppLifeCycle.class.getCanonicalName());
        return set;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.RELEASE_8;
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(AppLifeCycle.class);
        mMap.clear();
        for (Element element : elements) {
            if (!element.getKind().isClass()) {
                throw new RuntimeException("Annotation AppLifeCycle can only be used in class.");
            }
            TypeElement typeElement = (TypeElement) element;
            //这里检查一下,使用了该注解的类,同时必须要实现com.example.lifecycle.api.IAppLike接口,否则会报错,因为我们要实现一个代理类             
            List<? extends TypeMirror> mirrorList = typeElement.getInterfaces();
            if (mirrorList.isEmpty()) {
                throw new RuntimeException(typeElement.getQualifiedName() + " must implements interface com.example.lifecycle.api.IAppLike");
            }
            boolean checkInterfaceFlag = false;
            for (TypeMirror mirror : mirrorList) {
                if ("com.example.lifecycle.api.IAppLike".equals(mirror.toString())) {
                    checkInterfaceFlag = true;
                }
            }
            if (!checkInterfaceFlag) {
                throw new RuntimeException(typeElement.getQualifiedName() + " must implements interface com.example.lifecycle.api.IAppLike");
            }
            String fullClassName = typeElement.getQualifiedName().toString();
            if (!mMap.containsKey(fullClassName)) {
                System.out.println("process class name : " + fullClassName);
                AppLikeProxyClassCreator creator = new AppLikeProxyClassCreator(mElementUtils, typeElement);
                mMap.put(fullClassName, creator);
            }
        }
        System.out.println("start to generate proxy class code");
        for (Map.Entry<String, AppLikeProxyClassCreator> entry : mMap.entrySet()) {
            String className = entry.getKey();
            AppLikeProxyClassCreator creator = entry.getValue();
            System.out.println("generate proxy class for " + className);
            try {
                JavaFileObject jfo = processingEnv.getFiler().createSourceFile(creator.getProxyClassFullName());
                Writer writer = jfo.openWriter();
                writer.write(creator.generateJavaCode());
                writer.flush();
                writer.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return true;
    }
}
public class AppLikeProxyClassCreator {
    private Elements mElementUtils;
    private TypeElement mTypeElement;
    private String mProxyClassSimpleName;

    public AppLikeProxyClassCreator(Elements elements, TypeElement typeElement) {
        mElementUtils = elements;
        mTypeElement = typeElement;
        mProxyClassSimpleName = LifeCycleConfig.PROXY_CLASS_PREFIX + mTypeElement.getSimpleName().toString() + LifeCycleConfig.PROXY_CLASS_SUFFIX;
    }

    /**
     * 获取要生成的代理类的完整类名      *      * @return
     */
    public String getProxyClassFullName() {
        String name = LifeCycleConfig.PROXY_CLASS_PACKAGE_NAME + "." + mProxyClassSimpleName;
        return name;
    }

    /**
     * 生成java代码
     */
    public String generateJavaCode() {
        StringBuilder sb = new StringBuilder();
        //设置包名         
        sb.append("package ").append(LifeCycleConfig.PROXY_CLASS_PACKAGE_NAME).append(";nn");
        //设置import部分         
        sb.append("import android.content.Context;n");
        sb.append("import com.example.lifecycle.api.IAppLike;n");
        sb.append("import ").append(mTypeElement.getQualifiedName()).append(";nn");
        sb.append("public class ").append(mProxyClassSimpleName).append(" implements ").append("IAppLike ").append(" {nn");
        //设置变量         
        sb.append("  private ").append(mTypeElement.getSimpleName().toString()).append(" mAppLike;nn");
        //构造函数         
        sb.append("  public ").append(mProxyClassSimpleName).append("() {n");
        sb.append("  mAppLike = new ").append(mTypeElement.getSimpleName().toString()).append("();n");
        sb.append("  }nn");
        //getPriority()方法         
        sb.append("  public int getPriority() {n");
        sb.append("    return mAppLike.getPriority();n");
        sb.append("  }nn");
        //onCreate()方法         
        sb.append("  public void onCreate() {n");
        sb.append("    mAppLike.onCreate();n");
        sb.append("  }nn");
        //onTerminate方法         
        sb.append("  public void onTerminate() {n");
        sb.append("    mAppLike.onTerminate();n");
        sb.append("  }nn");
        //onTerminate方法         
        sb.append("  public void onLowMemory() {n");
        sb.append("    mAppLike.onLowMemory();n");
        sb.append("  }nn");
        //onTerminate方法        
        sb.append("  public void onTrimMemory(int level) {n");
        sb.append("    mAppLike.onTrimMemory(level);n");
        sb.append("  }nn");
        sb.append("n}");
        return sb.toString();
    }
}

关于APT的调试可以参考https://blog.csdn.net/zhangteng22/article/details/54946270这篇文章。

在前面定义的几个组件代理类上添加注解@AppLifeCycle

//实现了IAppLike接口,并且采用了AppLifeCycle注解,二者缺一不可,否则APT处理时会报错 
@AppLifeCycle
public class MainDelegate implements IAppLike {
    @Override
    public int getPriority() {
        return 10;
    }

    @Override
    public void onCreate() {
        Log.i("hx", "MainDelegate-onCreate");
    }

    @Override
    public void onTerminate() {
        Log.i("hx", "MainDelegate-onTerminate");
    }

    @Override
    public void onLowMemory() {
    }

    @Override
    public void onTrimMemory(int level) {
    }
}

同时修改组件的build.gradle,添加依赖:

//---------其他依赖------------     
api project(':lifecycle-annotation')     
api project(':lifecycle-api')     
//需要注意这里是使用 annotationProcessor,即我们刚定义的注解处理器     
annotationProcessor project(':lifecycle-apt')

到这里注解处理器就可以工作啦,将整个工程编译一下,可以看到在build目录下已经生成了我们定义的注解类,具体路径如下所示:
在这里插入图片描述
打开看一下呢:

public class Watson$$MainDelegate$$Proxy implements IAppLike {
    private MainDelegate mAppLike;

    public Watson$$MainDelegate$$Proxy() {
        mAppLike = new MainDelegate();
    }

    public int getPriority() {
        return mAppLike.getPriority();
    }

    public void onCreate() {
        mAppLike.onCreate();
    }

    public void onTerminate() {
        mAppLike.onTerminate();
    }

    public void onLowMemory() {
        mAppLike.onLowMemory();
    }

    public void onTrimMemory(int level) {
        mAppLike.onTrimMemory(level);
    }
}

重新定义IAppLike接口

新建一个Android Library module,命名为lifecycle-api,在这个module里定义IAppLike接口,以及一个生命周期管理类。现在工程目录差不多是这样的:
捕获.PNG

public interface IAppLike {
    int MAX_PRIORITY = 10;
    int MIN_PRIORITY = 1;
    int NORM_PRIORITY = 5;

    default int getPriority() {
        return NORM_PRIORITY;
    }

    void onCreate();

    void onTerminate();

    void onLowMemory();

    void onTrimMemory(int level);
}

生命周期管理类,初始化的时候扫描所有的代理辅助类,并在相应方法中调用组件生命周期方法。

public class AppLifeCycleManager {
    /**
     * 初始化
     */
    public static void init(Context context) {
        scanClassFile(context);
        Log.d("hx", "代理子模块数目:" + APP_LIKE_LIST.size());
        Collections.sort(APP_LIKE_LIST, new AppDelegateComparator()); //优先级排序    
    }

    public static void onCreate() {
        for (IAppLike delegate : APP_LIKE_LIST) {
            delegate.onCreate();
        }
    }

    public static void onTerminate() {
        for (IAppLike delegate : APP_LIKE_LIST) {
            delegate.onTerminate();
        }
    }

    public static void onLowMemory() {
        for (IAppLike delegate : APP_LIKE_LIST) {
            delegate.onLowMemory();
        }
    }

    public static void onTrimMemory(int level) {
        for (IAppLike delegate : APP_LIKE_LIST) {
            delegate.onTrimMemory(level);
        }
    }

    /**
     * 扫描出固定包名下,实现了
                        
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/huaxun66/article/details/103978740
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢