成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Android架構(gòu)進(jìn)階之深入理解AppStartup原理

移動(dòng)開(kāi)發(fā) Android
Android Startup提供一種在應(yīng)用啟動(dòng)時(shí)能夠更加簡(jiǎn)單、高效的方式來(lái)初始化組件。開(kāi)發(fā)人員可以使用Android Startup來(lái)簡(jiǎn)化啟動(dòng)序列,并顯式地設(shè)置初始化順序與組件之間的依賴(lài)關(guān)系。

[[422993]]

前言

Android Startup提供一種在應(yīng)用啟動(dòng)時(shí)能夠更加簡(jiǎn)單、高效的方式來(lái)初始化組件。開(kāi)發(fā)人員可以使用Android Startup來(lái)簡(jiǎn)化啟動(dòng)序列,并顯式地設(shè)置初始化順序與組件之間的依賴(lài)關(guān)系;

今天我們就來(lái)聊聊

一、使用步驟簡(jiǎn)單介紹

使用 AndroidX App Startup 來(lái)運(yùn)行所有依賴(lài)項(xiàng)的初始化有兩種方式:

自動(dòng)初始化;

手動(dòng)初始化(也是延遲初始化);

1、自動(dòng)初始化

在 build.gradle 文件內(nèi)添加依賴(lài);

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

實(shí)現(xiàn) Initializer 接口,并重寫(xiě)兩個(gè)方法,來(lái)初始化組件;

  1. public class MvpInitializer implements Initializer<Void> { 
  2.     @NonNull 
  3.     @Override 
  4.     public Void create(@NonNull Context context) { 
  5.          MvpManager.init(context); 
  6.          return null
  7.     } 
  8.     @NonNull 
  9.     @Override 
  10.     public List<Class<? extends Initializer<?>>> dependencies() { 
  11.         return new ArrayList<>(); 
  12.     } 
  13.     ...... 

create(Context): 這里進(jìn)行組件初始化工作;

dependencies(): 返回需要初始化的列表,同時(shí)設(shè)置 App 啟動(dòng)時(shí)依賴(lài)庫(kù)運(yùn)行的順序;

在 AndroidManifest.xml 文件中注冊(cè) InitializationProvider;

  1. <application> 
  2.         <provider 
  3.             android:authorities="${applicationId}.androidx-startup" 
  4.             android:name="androidx.startup.InitializationProvider" 
  5.             android:exported="false" 
  6.             tools:node="merge" > 
  7.           <!-- 自動(dòng)初始化 --> 
  8.             <meta-data android:name="com.test.Initializer" android:value="androidx.startup"/> 
  9.     </provider> 
  10. </application> 

 

 

App 啟動(dòng)的時(shí) App Startup 會(huì)讀取 AndroidManifest.xml 文件里面的 InitializationProvider 下面的 聲明要初始化的組件,完成自動(dòng)初始化工作;

2、手動(dòng)初始化(也是延遲初始化)

在 build.gradle 文件內(nèi)添加依賴(lài);

創(chuàng)建一個(gè)類(lèi) LibaryD 實(shí)現(xiàn) Initializer 接口,并重寫(xiě)兩個(gè)方法,來(lái)初始化組件;

在 AndroidManifest.xml 文件中注冊(cè) InitializationProvider

  1. <application> 
  2.         <provider 
  3.             android:name="androidx.startup.InitializationProvider" 
  4.             android:authorities="${applicationId}.androidx-startup" 
  5.             android:exported="false" 
  6.             tools:node="merge"
  7.             <!-- 手動(dòng)初始化(也是延遲初始化) --> 
  8.             <meta-data 
  9.                 android:name="com.test.Initializer" 
  10.                 android:value="androidx.startup" 
  11.                 tools:node="remove" /> 
  12.         </provider> 
  13.     </application> 

 

 

  • 只需要在 標(biāo)簽內(nèi)添加 tools:node="remove" 清單合并工具會(huì)將它從清單文件中刪除;
  • 在需要的地方進(jìn)行初始化,調(diào)用以下代碼進(jìn)行初始化;
  • Initializer.getInstance(context).initializeComponent(Initializer::class.java);
  • 如果組件初始化之后,再次調(diào)用 AppInitializer.initializeComponent() 方法不會(huì)再次初始化;
  • 手動(dòng)初始化(也是延遲初始化)是非常有用的,組件不需要在 App 啟動(dòng)時(shí)運(yùn)行,只需要在需要它地方運(yùn)行,可以減少 App 的啟動(dòng)時(shí)間,提高啟動(dòng)速度;

二、源碼分析

1、InitializationProvider

在AndroidManifest文件中配置的組件名必須為androidx.startup.InitializationProvider,現(xiàn)在我們來(lái)看這個(gè)類(lèi)的源碼;

  1. InitializationProvider.java 
  2. public final class InitializationProvider extends ContentProvider { 
  3.     @Override 
  4.     public boolean onCreate() { 
  5.         Context context = getContext(); 
  6.         if (context != null) { 
  7.             初始化 
  8.             AppInitializer.getInstance(context).discoverAndInitialize(); 
  9.         } else { 
  10.             throw new StartupException("Context cannot be null"); 
  11.         } 
  12.         return true
  13.     } 
  14.     @Override 
  15.     public Cursor query(...) { 
  16.         throw new IllegalStateException("Not allowed."); 
  17.     } 
  18.     @Override 
  19.     public String getType(...) { 
  20.         throw new IllegalStateException("Not allowed."); 
  21.     } 
  22.     @Nullable 
  23.     @Override 
  24.     public Uri insert(...) { 
  25.         throw new IllegalStateException("Not allowed."); 
  26.     } 
  27.     @Override 
  28.     public int delete(...) { 
  29.         throw new IllegalStateException("Not allowed."); 
  30.     } 
  31.     @Override 
  32.     public int update(...) { 
  33.         throw new IllegalStateException("Not allowed."); 
  34.     } 

InitializationProvider其實(shí)也是利用了 ContentProvider 的啟動(dòng)機(jī)制,在ContentProvider#onCreate(...)中執(zhí)行初始化;

ContentProvider 的其他方法是沒(méi)有意義的,所以都拋出了IllegalStateException;

2、自動(dòng)初始化分析

App Startup 在 ContentProvider 中調(diào)用了AppInitializer#discoverAndInitialize()執(zhí)行自動(dòng)初始化;

AppInitializer是 App StartUp 框架的核心類(lèi),整個(gè) App Startup 框架的代碼其實(shí)非常少,其中很大部分核心代碼都在 AppInitializer 類(lèi)中;

2.1.AppInitializer.java discoverAndInitialize

  1. final Set<Class<? extends Initializer<?>>> mDiscovered; 
  2. void discoverAndInitialize() { 
  3.     獲取 androidx.startup.InitializationProvider 組件信息 
  4.     ComponentName provider = new ComponentName(mContext.getPackageName(), InitializationProvider.class.getName()); 
  5.     ProviderInfo providerInfo = mContext.getPackageManager().getProviderInfo(provider, GET_META_DATA); 
  6.    androidx.startup 字符串 
  7.     String startup = mContext.getString(R.string.androidx_startup); 
  8.    獲取組件信息中的 meta-data 數(shù)據(jù) 
  9.     Bundle metadata = providerInfo.metaData; 
  10.     遍歷 meta-data 數(shù)據(jù) 
  11.     if (metadata != null) { 
  12.         Set<Class<?>> initializing = new HashSet<>(); 
  13.         Set<String> keys = metadata.keySet(); 
  14.         for (String key : keys) { 
  15.             String value = metadata.getString(keynull); 
  16.           判斷 meta-data 數(shù)據(jù)中,value 為 androidx.startup 的鍵值對(duì) 
  17.             if (startup.equals(value)) { 
  18.                 Class<?> clazz = Class.forName(key); 
  19.                  檢查指定的類(lèi)是 Initializer 接口的實(shí)現(xiàn)類(lèi) 
  20.                 if (Initializer.class.isAssignableFrom(clazz)) { 
  21.                     Class<? extends Initializer<?>> component = (Class<? extends Initializer<?>>) clazz; 
  22.                     將 Class 添加到 mDiscovered Set 中 
  23.                     mDiscovered.add(component); 
  24.                     初始化此組件 
  25.                     doInitialize(component, initializing); 
  26.                 } 
  27.             } 
  28.         } 
  29.     } 
  30. mDiscovered 用于判斷組件是否已經(jīng)自動(dòng)啟動(dòng) 
  31. public boolean isEagerlyInitialized(@NonNull Class<? extends Initializer<?>> component) { 
  32.     return mDiscovered.contains(component); 
  • 獲取androidx.startup.InitializationProvider組件信息(在各個(gè) Module 中聲明的組件信息,會(huì)在manifest merger tool的處理下合并);
  • androidx.startup字符串;
  • 獲取組件信息中的 meta-data 數(shù)據(jù);
  • 遍歷 meta-data 數(shù)據(jù);
  • 判斷 meta-data 數(shù)據(jù)中,value 為 androidx.startup 的鍵值對(duì);
  • 檢查指定的類(lèi)是 Initializer 接口的實(shí)現(xiàn)類(lèi);
  • 將 Class 添加到 mDiscovered Set 中,這將用于后續(xù) 判斷組件是否已經(jīng)自動(dòng)啟動(dòng);
  • 初始化此組件;

2.2.AppInitializer.java AppInitializer.java

  1. private static final Object sLock = new Object(); 
  2. 緩存每個(gè)組件的初始化結(jié)果; 
  3. final Map<Class<?>, Object> mInitialized; 
  4. 初始化此組件 
  5. <T> T doInitialize(Class<? extends Initializer<?>> component, Set<Class<?>> initializing) { 
  6.     對(duì) sLock 加鎖 
  7.     Object result; 
  8.   判斷 initializing 中存在當(dāng)前組件,說(shuō)明存在循環(huán)依賴(lài) 
  9.     if (initializing.contains(component)) { 
  10.         String message = String.format("Cannot initialize %s. Cycle detected.", component.getName()); 
  11.         throw new IllegalStateException(message); 
  12.     } 
  13.    檢查當(dāng)前組件是否已初始化 
  14.     if (!mInitialized.containsKey(component)) { 
  15.         當(dāng)前組件未初始化 
  16.         記錄正在初始化 
  17.         initializing.add(component); 
  18.         通過(guò)反射實(shí)例化 Initializer 接口實(shí)現(xiàn)類(lèi) 
  19.         Object instance = component.getDeclaredConstructor().newInstance(); 
  20.         Initializer<?> initializer = (Initializer<?>) instance; 
  21.        遍歷所依賴(lài)的組件 
  22.         List<Class<? extends Initializer<?>>> dependencies = initializer.dependencies(); 
  23.         if (!dependencies.isEmpty()) { 
  24.             for (Class<? extends Initializer<?>> clazz : dependencies) { 
  25.                 如果所依賴(lài)的組件未初始化,遞歸執(zhí)行初始化 
  26.                 if (!mInitialized.containsKey(clazz)) { 
  27.                     doInitialize(clazz, initializing); 注意:這里將 initializing 作為參數(shù)傳入 
  28.                 } 
  29.             } 
  30.         } 
  31.        初始化當(dāng)前組件 
  32.         result = initializer.create(mContext); 
  33.        移除正在初始化記錄 
  34.         initializing.remove(component); 
  35.         緩存初始化結(jié)果 
  36.         mInitialized.put(component, result); 
  37.     } else { 
  38.         當(dāng)前組件已經(jīng)初始化,直接返回 
  39.         result = mInitialized.get(component); 
  40.     } 
  41.      return (T) result; 
  • 對(duì) sLock 加鎖;
  • 判斷 initializing 中存在當(dāng)前組件,說(shuō)明存在循環(huán)依賴(lài)(這是因?yàn)檫f歸初始化所依賴(lài)的組件時(shí),會(huì)將 initializing 作為參數(shù)傳入,如果 initializing 中存在當(dāng)前組件,說(shuō)明依賴(lài)關(guān)系形成回環(huán),如果不拋出異常,將形成無(wú)限遞歸);
  • 檢查當(dāng)前組件是否已初始化;
  • 記錄正在初始化;
  • 通過(guò)反射實(shí)例化 Initializer 接口實(shí)現(xiàn)類(lèi);
  • 遍歷所依賴(lài)的組件,如果所依賴(lài)的組件未初始化,遞歸調(diào)用doInitialize(...)執(zhí)行初始化;
  • 初始化當(dāng)前組件;
  • 移除正在初始化記錄;
  • 緩存初始化結(jié)果;

3、手動(dòng)初始化源碼分析

手動(dòng)初始化(懶加載)的源碼分析:

  1. AppInitializer.java 
  2. public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) { 
  3.     調(diào)用 doInitialize(...) 方法: 
  4.     return doInitialize(component, new HashSet<Class<?>>()); 

其實(shí)非常簡(jiǎn)單,就是調(diào)用上一節(jié)的doInitialize(...)執(zhí)行初始化。需要注意的是,這個(gè)方法是允許在子線程調(diào)用的,換句話說(shuō),自動(dòng)初始化與手動(dòng)初始化是存在線程同步問(wèn)題的,那么 App Startup 是如何解決的呢?

前面有一個(gè)sLock沒(méi)有說(shuō)嗎?其實(shí)它就是用來(lái)保證線程同步的鎖:

  1. <T> T doInitialize(Class<? extends Initializer<?>> component, Set<Class<?>> initializing) { 
  2.    對(duì) sLock 加鎖 
  3.     synchronized (sLock) { 
  4.         ...  
  5.     } 

總結(jié)

App Startup 是 Jetpack 的新成員,是為了解決因 App 啟動(dòng)時(shí)運(yùn)行多個(gè) ContentProvider 會(huì)增加 App 的啟動(dòng)時(shí)間的問(wèn)題;

使用了一個(gè) InitializationProvider 管理多個(gè)依賴(lài)項(xiàng),消除了每個(gè)庫(kù)單獨(dú)使用 ContentProvider 成本,減少初始化時(shí)間;

App Startup 允許你自定義組件初始化順序;

 

App Startup 提供了一種延遲初始化組件的方法,減少 App 初始化時(shí)間;

 

責(zé)任編輯:武曉燕 來(lái)源: Android開(kāi)發(fā)編程
相關(guān)推薦

2021-09-08 06:51:52

AndroidRetrofit原理

2021-10-15 09:19:17

AndroidSharedPrefe分析源碼

2021-09-17 06:55:50

AndroidLayoutView

2022-09-05 22:22:00

Stream操作對(duì)象

2022-01-14 12:28:18

架構(gòu)OpenFeign遠(yuǎn)程

2021-08-24 07:53:28

AndroidActivity生命周期

2018-12-27 12:34:42

HadoopHDFS分布式系統(tǒng)

2019-03-18 09:50:44

Nginx架構(gòu)服務(wù)器

2023-01-16 18:32:15

架構(gòu)APNacos

2014-07-15 17:17:31

AdapterAndroid

2021-09-16 06:44:04

Android進(jìn)階流程

2021-09-24 08:10:40

Java 語(yǔ)言 Java 基礎(chǔ)

2017-08-08 09:15:41

前端JavaScript頁(yè)面渲染

2021-10-26 17:52:52

Android插件化技術(shù)

2021-09-15 07:31:33

Android窗口管理

2017-08-15 13:05:58

Serverless架構(gòu)開(kāi)發(fā)運(yùn)維

2021-02-17 11:25:33

前端JavaScriptthis

2021-09-30 07:36:51

AndroidViewDraw

2021-10-10 13:31:14

Java負(fù)載均衡算法

2021-10-21 10:02:37

Java開(kāi)發(fā)代碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 久久久福利| 国产精品美女久久久久久不卡 | 国产一区二区三区色淫影院 | 成人精品鲁一区一区二区 | 亚洲一区日韩 | 国产一区二区欧美 | 亚洲免费在线视频 | 99国内精品久久久久久久 | 国产精久久久久久久 | av在线免费观看网站 | 午夜精品久久久久久久星辰影院 | 亚洲国产高清在线观看 | 日日碰狠狠躁久久躁婷婷 | 精品国产青草久久久久福利 | 91精品国产一区二区三区动漫 | 欧美不卡在线 | 精品国产一区二区三区av片 | 99re视频在线 | 精品久久久久久国产 | 日本国产精品视频 | 亚洲国产欧美在线 | 69av网| 最新中文字幕久久 | 精品欧美一区二区三区精品久久 | 国产在线精品一区二区三区 | 国产午夜精品一区二区三区四区 | 亚洲午夜精品在线观看 | 国产欧美精品一区 | av中文天堂 | 日韩欧美中文字幕在线观看 | 天色综合网 | 国产91中文| 成人久久视频 | 国产一区二区三区日韩 | 国产精品久久国产精品久久 | 中文字幕精品一区久久久久 | 日本小电影在线 | 一区二区三区小视频 | 五月免费视频 | 久在线视频 | 欧美区在线 |