(4.6.30.1)组件化:Application离散式注册方案


Application离散式注册方案

一、Application功能分析

在Android开发当中,一个APP有且只能有一个全局的Application对象,而且如果需要自定义的话,必须在AndroidManifest.xml中配置

Application的使用主要涉及以下两个功能:

  1. 入侵生命周期
    Application具备attachBaseContext()、onCreate()等生命周期函数,它会在app启动过程中被系统触发
    我们可以重写对应方法,实现一些需要提前初始化的功能,譬如MultiDex、初始化推送等
  2. 全局单例模式
    Application是全局单例模式,而且相对于普通static对象,具有更强的引用关系,内部存储的变量基本在应用存活期间一直存有
    我们往往利用这一点,在Application中存储稳定性要求更好的单例变量,譬如已登录用户的信息等

二、问题分析

在上文的分析中,我们已经说到,我们的业务需要入侵到Application中,也就是说 Application中必须持有 业务类的引用,相当于Application强依赖了业务代码,如下图所示

在这里插入图片描述
【图 Application依赖】

然而,在组件化模型中,我们需要将Application独立出去,也就是说业务层处于上层中,如下图所示:

在这里插入图片描述

此时,Application中已经不能持有业务的任何引用了

那么,我们需要一种方式去支持一种离散式Application[入侵生命周期]和[全局单例模式]使用;

三、入侵生命周期的离散式实现

Applcation的生命周期是在启动任何一个Activity之前就完成的,因此我们必须在系统启动应用的时候:

  1. Application主动去收集各个业务层需要入侵生命周期的回调
  2. 在系统触发Application的对应生命周期时,Applcation自动去触发业务层的回调

我们定义一个生命周期接口:

public interface ApplicationLifecycles {

    void attachBaseContext(@NonNull Context base);

    void onCreate(@NonNull Application application);

    void onTerminate(@NonNull Application application);

}

然后想办法,让上层业务代码能主动的向某个地方去注册自己的实现,然后Application在启动时自动去收集,就可以实现一直“被动注册”逻辑

我们利用AndroidManifest.xml的属性,原因如下:

  1. [插拔式]:业务代码可以在自己module的AndroidManifest.xml中配置自己的属性,最终会被合并到唯一的AndroidManifest.xml中。
  2. [独立性]: 业务代码仅在自己的module中去维护自己需要入侵的 生命周期业务,便于后期的维护

为此,我们需要定义一个处理类:

public interface ModularAppConfiger {

	
    /**
     * 使用{@link ApplicationLifecycles}在Application的生命周期中注入一些操作
     *
     * @param context
     * @param lifecycles
     */
    void injectAppLifecycle(Context context, List<ApplicationLifecycles> lifecycles);

}

各个业务module实现该接口,并注册到 AndroidManifest.xml中

<meta-data
	android:name="me.jessyan.mvparms.demo.app.GlobalConfiguration"
	android:value="ModularAppConfiger"/>

然后,Application中去解析和反射,就可以持有对应回调:


private List<ApplicationLifecycles> mAppLifecycles = new ArrayList<>();
	
public List<ModularAppConfiger> parse() {
        List<ModularAppConfiger> modules = new ArrayList<ModularAppConfiger>();
        try {
            ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
                    context.getPackageName(), PackageManager.GET_META_DATA);
            if (appInfo.metaData != null) {
                for (String key : appInfo.metaData.keySet()) {
                    if (MODULE_VALUE.equals(appInfo.metaData.get(key))) {
                        modules.add(parseModule(key));
                    }
                }
            }
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException("Unable to find metadata to parse ModularAppConfiger", e);
        }

        return modules;
    }

    private static ModularAppConfiger parseModule(String className) {
        Class<?> clazz;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException("Unable to find ModularAppConfiger implementation", e);
        }

        Object module;
        try {
            module = clazz.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException("Unable to instantiate ModularAppConfiger implementation for " + clazz, e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Unable to instantiate ModularAppConfiger implementation for " + clazz, e);
        }

        if (!(module instanceof ModularAppConfiger)) {
            throw new RuntimeException("Expected instanceof ModularAppConfiger, but found: " + module);
        }
        return (ModularAppConfiger) module;
    }

最终在自己的生命周期函数中触发相关回调:

    @Override
    public void attachBaseContext(@NonNull Context base) {

        //(执行框架外部, 开发者扩展的逻辑)
        //遍历 mAppLifecycles, 执行所有已注册的 AppLifecycles 的 attachBaseContext() 方法
        for (ApplicationLifecycles lifecycle : mAppLifecycles) {
            lifecycle.attachBaseContext(base);
        }
    }

在这里插入图片描述

四、全局单例模式的离散式使用

由于Applicaiton是全局唯一的,所以Applicaiton中持有的实例也是全局唯一的

我们知道java在内存不足的情况下,会自动触发内存回收机制,而Application中的内存在应用使用期间一般是不会被回收的

这也是为什么不能简单地使用静态单例模式来替换Applicaiton中变量的使用;

具体的实现方式,是我们定义一个接口,这个接口会返回一个单例模式的Cache缓存:

public interface AppSingleton {

    //用来存取一些整个App公用的数据,切勿大量存放大容量数据
    Cache<String, Object> extras();

    //用于创建框架所需缓存对象的工厂
    Cache.Factory cacheFactory();

}

在Application中,实例化该接口的具体类,并持有该实例

 private AppSingleton mAppSingleton;

当然了,具体的实例化过程,我们也允许上层业务来自定义,还是借助上文的ModularAppConfiger,我们允许上层的业务代码自动配置缓存结构

public interface ModularAppConfiger {

	    /**
     * 使用{@link AppSingletonConfig.Builder}给框架配置一些配置参数
     *
     * @param context
     * @param builder
     */
    void applyOptions(Context context, AppSingletonConfig.Builder builder);

}

public interface AppSingleton {

    //用来存取一些整个App公用的数据,切勿大量存放大容量数据
    Cache<String, Object> extras();

    //用于创建框架所需缓存对象的工厂
    Cache.Factory cacheFactory();

}

然后我们在Application中实现对应的功能,具体的代码不再赘述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值