行业动态 Android架构进阶之深入理解AppStartup原理


admin| 更新时间:2021-09-09 23:35|点击数:未知

序言

Android Startup挑供一栽在行使启动时能够更添浅易、高效的手段来初首化组件。开发人员能够行使Android Startup来简化启动序列,并显式地竖立初首化挨次与组件之间的倚赖有关;

今天吾们就来聊聊

新华社北京5月5日电(记者刘夏村)记者5日从应急管理部获悉,截至当日20时,“五一”假期期间全国安全形势总体平稳,未发生重特大生产安全事故和自然灾害。

中新网5月6日电 据国家卫健委网站消息,5月5日0—24时,31个省(自治区、直辖市)和新疆生产建设兵团报告新增确诊病例5例,均为境外输入病例(四川2例,云南2例,广东1例);无新增死亡病例;新增疑似病例1例,为境外输入病例(在上海)。

5月5日0-24时,全省新增境外输入确诊病例1例,广州报告,来自喀麦隆。新增境外输入无症状感染者1例,广州报告,来自科特迪瓦。新增出院3例。

羊城晚报全媒体记者马灿、通讯员沈甸报道:5月4日傍晚,受强雷雨云团影响,广东地区暴雨倾盆、电闪雷鸣。南方电网广东电网公司全力迎战各地暴雨,保居民用电安全。截至5月5日下午4时,5.2万受影响用户已全部复电。

羊城晚报全媒体记者李志文、通讯员刘雅摄影报道:“五一”假期,由于“补偿式”探亲、旅游观光等客流交织,广州南站客流呈现假期头尾长途多、中间短途多、总体高位运行的特征。

一、行使步骤浅易介绍

行使 AndroidX App Startup 来运走一切倚赖项的初首化有两栽手段:

自动初首化;

手动初首化(也是耽延初首化);

1、自动初首化

在 build.gradle 文件内增补倚赖;

implementation "androidx.startup:startup-runtime:1.0.0-alpha01" 

实现 Initializer 接口,并重写两个手段,来初首化组件;

public class MvpInitializer implements Initializer<Void> {     @NonNull     @Override     public Void create(@NonNull Context context) {          MvpManager.init(context);          return null;     }     @NonNull     @Override     public List<Class<? extends Initializer<?>>> dependencies() {         return new ArrayList<>();     } }     ...... } 

create(Context): 这边进走组件初首化做事;

dependencies(): 返回必要初首化的列外行业动态,同时竖立 App 启动时倚赖库运走的挨次;

在 AndroidManifest.xml 文件中注册 InitializationProvider;

<application>         <provider             android:authorities="${applicationId}.androidx-startup"             android:name="androidx.startup.InitializationProvider"             android:exported="false"             tools:node="merge" >           <!-- 自动初首化 -->             <meta-data android:name="com.test.Initializer" android:value="androidx.startup"/>     </provider> </application

App 启动的时 App Startup 会读取 AndroidManifest.xml 文件内里的 InitializationProvider 下面的 声明要初首化的组件,完善自动初首化做事;

2、手动初首化(也是耽延初首化)

在 build.gradle 文件内增补倚赖;

创建一个类 LibaryD 实现 Initializer 接口,并重写两个手段,来初首化组件;

在 AndroidManifest.xml 文件中注册 InitializationProvider

<application>         <provider             android:name="androidx.startup.InitializationProvider"             android:authorities="${applicationId}.androidx-startup"             android:exported="false"             tools:node="merge">             <!-- 手动初首化(也是耽延初首化) -->             <meta-data                 android:name="com.test.Initializer"                 android:value="androidx.startup"                 tools:node="remove" />         </provider>     </application
只必要在 标签内增补 tools:node="remove" 清单相符并工具会将它从清单文件中删除; 在必要的地方进走初首化,调用以下代码进走初首化; Initializer.getInstance(context).initializeComponent(Initializer::class.java); 倘若组件初首化之后,再次调用 AppInitializer.initializeComponent() 手段不会再次初首化; 手动初首化(也是耽延初首化)是专门有用的,组件不必要在 App 启动时运走,只必要在必要它地方运走,能够缩短 App 的启动时间,挑高启动速度; 二、源码分析

1、InitializationProvider

在AndroidManifest文件中配置的组件名必须为androidx.startup.InitializationProvider,现在吾们来望这个类的源码;

InitializationProvider.java public final class InitializationProvider extends ContentProvider {     @Override     public boolean onCreate() {         Context context = getContext();         if (context != null) {             初首化             AppInitializer.getInstance(context).discoverAndInitialize();         } else {             throw new StartupException("Context cannot be null");         }         return true;     }     @Override     public Cursor query(...) {         throw new IllegalStateException("Not allowed.");     }     @Override     public String getType(...) {         throw new IllegalStateException("Not allowed.");     }     @Nullable     @Override     public Uri insert(...) {         throw new IllegalStateException("Not allowed.");     }     @Override     public int delete(...) {         throw new IllegalStateException("Not allowed.");     }     @Override     public int update(...) {         throw new IllegalStateException("Not allowed.");     } } 

InitializationProvider其实也是行使了 ContentProvider 的启动机制,在ContentProvider#onCreate(...)中实走初首化;

ContentProvider 的其他手段是异国意义的,于是都抛出了IllegalStateException;

2、自动初首化分析

App Startup 在 ContentProvider 中调用了AppInitializer#discoverAndInitialize()实走自动初首化;

AppInitializer是 App StartUp 框架的中央类,整个 App Startup 框架的代码其实专门少,其中很大片面中央代码都在 AppInitializer 类中;

2.1.AppInitializer.java discoverAndInitialize

final Set<Class<? extends Initializer<?>>> mDiscovered; void discoverAndInitialize() {     获取 androidx.startup.InitializationProvider 组件新闻     ComponentName provider = new ComponentName(mContext.getPackageName(), InitializationProvider.class.getName());     ProviderInfo providerInfo = mContext.getPackageManager().getProviderInfo(provider, GET_META_DATA);    androidx.startup 字符串     String startup = mContext.getString(R.string.androidx_startup);    获取组件新闻中的 meta-data 数据     Bundle metadata = providerInfo.metaData;     遍历 meta-data 数据     if (metadata != null) {         Set<Class<?>> initializing = new HashSet<>();         Set<String> keys = metadata.keySet();         for (String key : keys) {             String value = metadata.getString(key, null);           判定 meta-data 数据中,value 为 androidx.startup 的键值对             if (startup.equals(value)) {                 Class<?> clazz = Class.forName(key);                  检查指定的类是 Initializer 接口的实现类                 if (Initializer.class.isAssignableFrom(clazz)) {                     Class<? extends Initializer<?>> component = (Class<? extends Initializer<?>>) clazz;                     将 Class 增补到 mDiscovered Set 中                     mDiscovered.add(component);                     初首化此组件                     doInitialize(component, initializing);                 }             }         }     } } mDiscovered 用于判定组件是否已经自动启动 public boolean isEagerlyInitialized(@NonNull Class<? extends Initializer<?>> component) {     return mDiscovered.contains(component); } 
获取androidx.startup.InitializationProvider组件新闻(在各个 Module 中声明的组件新闻,会在manifest merger tool的处理下相符并); androidx.startup字符串; 获取组件新闻中的 meta-data 数据; 遍历 meta-data 数据; 判定 meta-data 数据中,value 为 androidx.startup 的键值对; 检查指定的类是 Initializer 接口的实现类; 将 Class 增补到 mDiscovered Set 中,这将用于后续 判定组件是否已经自动启动; 初首化此组件;

2.2.AppInitializer.java AppInitializer.java

private static final Object sLock = new Object(); 缓存每个组件的初首化效果; final Map<Class<?>, Object> mInitialized; 初首化此组件 <T> T doInitialize(Class<? extends Initializer<?>> component, Set<Class<?>> initializing) {     对 sLock 添锁     Object result;   判定 initializing 中存在现在组件,表明存在循环倚赖     if (initializing.contains(component)) {         String message = String.format("Cannot initialize %s. Cycle detected.", component.getName());         throw new IllegalStateException(message);     }    检查现在组件是否已初首化     if (!mInitialized.containsKey(component)) {         现在组件未初首化         记录正在初首化         initializing.add(component);         议决逆射实例化 Initializer 接口实现类         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); 仔细:这边将 initializing 行为参数传入                 }             }         }        初首化现在组件         result = initializer.create(mContext);        移除正在初首化记录         initializing.remove(component);         缓存初首化效果         mInitialized.put(component, result);     } else {         现在组件已经初首化,直接返回         result = mInitialized.get(component);     }      return (T) result; } 
对 sLock 添锁; 判定 initializing 中存在现在组件,表明存在循环倚赖(这是由于递归初首化所倚赖的组件时,会将 initializing 行为参数传入,倘若 initializing 中存在现在组件,表明倚赖有关形成回环,倘若不抛出变态,将形成无限递归); 检查现在组件是否已初首化; 记录正在初首化; 议决逆射实例化 Initializer 接口实现类; 遍历所倚赖的组件,倘若所倚赖的组件未初首化,递归调用doInitialize(...)实走初首化; 初首化现在组件; 移除正在初首化记录; 缓存初首化效果; 3、手动初首化源码分析

手动初首化(懒添载)的源码分析:

AppInitializer.java public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) {     调用 doInitialize(...) 手段:     return doInitialize(component, new HashSet<Class<?>>()); } 

其实专门浅易,就是调用上一节的doInitialize(...)实走初首化。必要仔细的是,这个手段是批准在子线程调用的,换句话说,自动初首化与手动初首化是存在线程同步题目的,那么 App Startup 是如何解决的呢?

前线有一个sLock异国说吗?其实它就是用来保证线程同步的锁:

<T> T doInitialize(Class<? extends Initializer<?>> component, Set<Class<?>> initializing) {    对 sLock 添锁     synchronized (sLock) {         ...      } } 
总结

App Startup 是 Jetpack 的新成员,是为晓畅决因 App 启动时运走众个 ContentProvider 会增补 App 的启动时间的题目;

行使了一个 InitializationProvider 管理众个倚赖项,清除了每个库单独行使 ContentProvider 成本,缩短初首化时间;

App Startup 批准你自定义组件初首化挨次;

App Startup 挑供了一栽耽延初首化组件的手段,缩短 App 初首化时间;

【编辑选举】行业动态

深度剖析Github上15.1k Star项现在:Redux-Thunk Python项现在实战篇-常用验证码标注和识别 行使 Vscode snippets 和项现在成员一首挑高开发效果 一文晓畅跨链桥设计类型及项现在分布 Jira 迅速项现在管理落地实战

友情链接

Powered by 亚博登录手机版-亚搏体育官网app下载 @2018 RSS地图 HTML地图