[Jetpack] - App Startup 源码学习

目录

一、使用:

二、学习源码:

2.1、总体源码学习介绍

 2.2、正式源码学习

2.2.1、InitializationProvider的学习

2.2.2、Initializer的学习

2.2.3、AppInitializer的学习(重点学习)


一、使用:

Android 开发者文档 

二、学习源码:

2.1、总体源码学习介绍

如下图所示:就三个类我们需要关注,其中我们需要学习的是就是一个类AppInitializer

 2.2、正式源码学习

2.2.1、InitializationProvider的学习

    @Override
    public boolean onCreate() {
        Context context = getContext();
        if (context != null) {
            // 就干一件事情:发现并初始化Initializer
            AppInitializer.getInstance(context).discoverAndInitialize();
        } else {
            throw new StartupException("Context cannot be null");
        }
        return true;
    }

第一就是在ContentProvider中onCreate去调用主操作函数初始化Initializer,看源码可以看到一个重要信息:initializes them before {@link Application#onCreate()} 即会在Application一开始被调用。

所以我们的注意力集中在AppInitializer前先看一下接口Initializer吧

2.2.2、Initializer的学习

public interface Initializer<T> {

    /**
     * Initializes and a component given the application {@link Context}
     *
     * @param context The application context.
     */
    @NonNull
    T create(@NonNull Context context);

    /**
     * @return A list of dependencies that this {@link Initializer} depends on. This is
     * used to determine initialization order of {@link Initializer}s.
     * <br/>
     * For e.g. if a {@link Initializer} `B` defines another
     * {@link Initializer} `A` as its dependency, then `A` gets initialized before `B`.
     */
    @NonNull
    List<Class<? extends Initializer<?>>> dependencies();
}

泛型的接口,create方法需要返回你想要的类型,在这个函数中去做想要的初始化操作即可;

dependencies方法正如注释上说的:如果你定义一个myOneInitializer implements Initializer<Boolean> 但是你需要在初始myOneInitializer前还需要初始化一个myTwoInitializer implements Initializer<Object>,那么你就需要在dependencies中做依赖即new ArrayList().add(myTwoInitializer()),这个必须需要提供一个无参构造哦。

下面我们重点学习下AppInitializer是如何为我们注入操作的吧。

2.2.3、AppInitializer的学习(重点学习)

单例的学习,对的,AppInitializer是单例的。同步锁sLock

    public static AppInitializer getInstance(@NonNull Context context) {
        if (sInstance == null) {
            synchronized (sLock) {
                if (sInstance == null) {
                    sInstance = new AppInitializer(context);
                }
            }
        }
        return sInstance;
    }

初始化处理重点关注两个全局变量:

final Set<Class<? extends Initializer<?>>> mDiscovered; // set集合收集初始化完毕的Initializer类

final Map<Class<?>, Object> mInitialized;// map以Initializer类为键,记得Initializer中的create的泛型吧,对就是它作为值

    AppInitializer(@NonNull Context context) {
        mContext = context.getApplicationContext();
        mDiscovered = new HashSet<>();
        mInitialized = new HashMap<>();
    }

大家可能还有印象,我们InitializerProvider中可是调用了discoverAndInitialize函数,那么它做了什么操作呢?

    void discoverAndInitialize() {
        try {
            Trace.beginSection(SECTION_NAME);
            ComponentName provider = new ComponentName(mContext.getPackageName(),
                    InitializationProvider.class.getName());
            ProviderInfo providerInfo = mContext.getPackageManager()
                    .getProviderInfo(provider, GET_META_DATA);
            Bundle metadata = providerInfo.metaData;
            String startup = mContext.getString(R.string.androidx_startup);
            if (metadata != null) {
                Set<Class<?>> initializing = new HashSet<>();
                Set<String> keys = metadata.keySet();
                for (String key : keys) {
                    String value = metadata.getString(key, null);
                    if (startup.equals(value)) {
                        Class<?> clazz = Class.forName(key);
                        if (Initializer.class.isAssignableFrom(clazz)) {
                            Class<? extends Initializer<?>> component =
                                    (Class<? extends Initializer<?>>) clazz;
                            mDiscovered.add(component);
                            if (StartupLogger.DEBUG) {
                                StartupLogger.i(String.format("Discovered %s", key));
                            }
                            doInitialize(component, initializing);
                        }
                    }
                }
            }
        } catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) {
            throw new StartupException(exception);
        } finally {
            Trace.endSection();
        }
    }

先大致看一下,下面我一一学习分析下吧。

首先,获取Manifest.xml中的Provider的meta-data信息,先插补一下清单文件的核心点吧。

        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false"
            tools:node="merge">
            <!--使用者只需要添加meta_data的自己实现的Initializer,注意的是value必须是下面这个字符串,因为这个在实现时定死了,哈哈-->
            <meta-data
                android:name="com.qzx.ble.BleInitializer"
                android:value="androidx.startup" />
        </provider>

大家看到了tools:node="merge"标签了吧,这个时manifest的标签,用于manifes合并的处理,这个知识参见谷歌Android文档吧。所以我们第一步需要获取所有的InitializationProvider的所有meta-data的数据,然后去一一初始化。

// 创建要搜索的InitializationProvider的组件名对象  
ComponentName provider = new ComponentName(mContext.getPackageName(),
                    InitializationProvider.class.getName());

// 拿到包管理器对象后按照meta-data标签获取内容提供者Provider的清单信息对象 
ProviderInfo providerInfo = mContext.getPackageManager()
                    .getProviderInfo(provider, GET_META_DATA);

// 获取InitializationProvider下的所有meta-data的信息,用Bundle包装
Bundle metadata = providerInfo.metaData;

见注释,拿取到meta-data的Bundle类。

下面的代码可以看到,取的时keySet,那么即取得是所有我们要实现的Initializer的类的set集合,看到了吧,通过key发现value是否等于字符串‘androidx.startup’,如果这个条件满足了,创建Class对象,然后还去判断是否是继承于Initializer

Initializer.class.isAssignableFrom(clazz)

这个函数返回true,如果是一样的class,或者是Object对象的基本基础类型,以及继承、实现于其超类等,这个函数值得学习和使用,这里因为我们都是实现了Initializer的接口,所以会筛选出所有实现了Initalizer接口的实现类。然后去调用下一个重要的实现函数:doInitialize(component, initializing);在这里大家也看到了需要把这个class加入和hashset中,因为这里算是发现了一个Initializer了。

mDiscovered.add(component);
if (StartupLogger.DEBUG) {
    StartupLogger.i(String.format("Discovered %s", key));
}
doInitialize(component, initializing);

 在doInitialize中,先看源码如下:

<T> T doInitialize(
            @NonNull Class<? extends Initializer<?>> component,
            @NonNull Set<Class<?>> initializing) {
        synchronized (sLock) {
            boolean isTracingEnabled = Trace.isEnabled();
            try {
                ...
                if (initializing.contains(component)) {
                    String message = String.format(
                            "Cannot initialize %s. Cycle detected.", component.getName()
                    );
                    throw new IllegalStateException(message);
                }
                Object result;
                if (!mInitialized.containsKey(component)) {
                    initializing.add(component);
                    try {
                        Object instance = component.getDeclaredConstructor().newInstance();
                        Initializer<?> initializer = (Initializer<?>) instance;
                        List<Class<? extends Initializer<?>>> dependencies =
                                initializer.dependencies();

                        if (!dependencies.isEmpty()) {
                            for (Class<? extends Initializer<?>> clazz : dependencies) {
                                if (!mInitialized.containsKey(clazz)) {
                                    doInitialize(clazz, initializing);
                                }
                            }
                        }
                        if (StartupLogger.DEBUG) {
                            StartupLogger.i(String.format("Initializing %s", component.getName()));
                        }
                        result = initializer.create(mContext);
                        if (StartupLogger.DEBUG) {
                            StartupLogger.i(String.format("Initialized %s", component.getName()));
                        }
                        initializing.remove(component);
                        mInitialized.put(component, result);
                    } catch (Throwable throwable) {
                        throw new StartupException(throwable);
                    }
                } else {
                    result = mInitialized.get(component);
                }
                return (T) result;
            } finally {
                Trace.endSection();
            }
        }
    }

大家简单看一遍,首先从hashmap的mInitialized中去找是否已经初始化过了,如果没有走主要的逻辑了,看。

           initializing.add(component);
           try {
               Object instance = component.getDeclaredConstructor().newInstance();
               Initializer<?> initializer = (Initializer<?>) instance;
               List<Class<? extends Initializer<?>>> dependencies =
                   initializer.dependencies();

               if (!dependencies.isEmpty()) {
                   for (Class<? extends Initializer<?>> clazz : dependencies) {
                       if (!mInitialized.containsKey(clazz)) {
                           doInitialize(clazz, initializing);
                       }
                   }
               }
                ...
               result = initializer.create(mContext);
               ...
                initializing.remove(component);
                mInitialized.put(component, result);
            } catch (Throwable throwable) {
               throw new StartupException(throwable);
            }

通过class类反射获取实现的Initialize的默认构造后创建相应的对象首先获取其dependencies(),结合上面说的,这个函数里面的Initialize是需要被先依赖进去的,所以,中间的for循环就是去先初始化所依赖的Initialize,同时初始化完毕塞入hashmap的mInitialized中。

值得注意的是doInitialize需要传递一个Set<class<?>>这个集合干的事就是一个,确保只会初始化一次Initialize,可见看到一开始 initializing.add(component); 创建后 initializing.remove(component);移除掉。

最后提一嘴:初始化依赖中用到了递归哦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值