自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

[[422993]]

前言

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

今天我們就來聊聊

一、使用步驟簡單介紹

使用 AndroidX App Startup 來運行所有依賴項的初始化有兩種方式:

自動初始化;

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

1、自動初始化

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

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

實現(xiàn) Initializer 接口,并重寫兩個方法,來初始化組件;

  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): 這里進行組件初始化工作;

dependencies(): 返回需要初始化的列表,同時設(shè)置 App 啟動時依賴庫運行的順序;

在 AndroidManifest.xml 文件中注冊 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.           <!-- 自動初始化 --> 
  8.             <meta-data android:name="com.test.Initializer" android:value="androidx.startup"/> 
  9.     </provider> 
  10. </application> 

 

 

App 啟動的時 App Startup 會讀取 AndroidManifest.xml 文件里面的 InitializationProvider 下面的 聲明要初始化的組件,完成自動初始化工作;

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

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

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

在 AndroidManifest.xml 文件中注冊 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.             <!-- 手動初始化(也是延遲初始化) --> 
  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" 清單合并工具會將它從清單文件中刪除;
  • 在需要的地方進行初始化,調(diào)用以下代碼進行初始化;
  • Initializer.getInstance(context).initializeComponent(Initializer::class.java);
  • 如果組件初始化之后,再次調(diào)用 AppInitializer.initializeComponent() 方法不會再次初始化;
  • 手動初始化(也是延遲初始化)是非常有用的,組件不需要在 App 啟動時運行,只需要在需要它地方運行,可以減少 App 的啟動時間,提高啟動速度;

二、源碼分析

1、InitializationProvider

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

  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其實也是利用了 ContentProvider 的啟動機制,在ContentProvider#onCreate(...)中執(zhí)行初始化;

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

2、自動初始化分析

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

AppInitializer是 App StartUp 框架的核心類,整個 App Startup 框架的代碼其實非常少,其中很大部分核心代碼都在 AppInitializer 類中;

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 的鍵值對 
  17.             if (startup.equals(value)) { 
  18.                 Class<?> clazz = Class.forName(key); 
  19.                  檢查指定的類是 Initializer 接口的實現(xiàn)類 
  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)自動啟動 
  31. public boolean isEagerlyInitialized(@NonNull Class<? extends Initializer<?>> component) { 
  32.     return mDiscovered.contains(component); 
  • 獲取androidx.startup.InitializationProvider組件信息(在各個 Module 中聲明的組件信息,會在manifest merger tool的處理下合并);
  • androidx.startup字符串;
  • 獲取組件信息中的 meta-data 數(shù)據(jù);
  • 遍歷 meta-data 數(shù)據(jù);
  • 判斷 meta-data 數(shù)據(jù)中,value 為 androidx.startup 的鍵值對;
  • 檢查指定的類是 Initializer 接口的實現(xiàn)類;
  • 將 Class 添加到 mDiscovered Set 中,這將用于后續(xù) 判斷組件是否已經(jīng)自動啟動;
  • 初始化此組件;

2.2.AppInitializer.java AppInitializer.java

  1. private static final Object sLock = new Object(); 
  2. 緩存每個組件的初始化結(jié)果; 
  3. final Map<Class<?>, Object> mInitialized; 
  4. 初始化此組件 
  5. <T> T doInitialize(Class<? extends Initializer<?>> component, Set<Class<?>> initializing) { 
  6.     對 sLock 加鎖 
  7.     Object result; 
  8.   判斷 initializing 中存在當(dāng)前組件,說明存在循環(huán)依賴 
  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.         通過反射實例化 Initializer 接口實現(xiàn)類 
  19.         Object instance = component.getDeclaredConstructor().newInstance(); 
  20.         Initializer<?> initializer = (Initializer<?>) instance; 
  21.        遍歷所依賴的組件 
  22.         List<Class<? extends Initializer<?>>> dependencies = initializer.dependencies(); 
  23.         if (!dependencies.isEmpty()) { 
  24.             for (Class<? extends Initializer<?>> clazz : dependencies) { 
  25.                 如果所依賴的組件未初始化,遞歸執(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; 
  • 對 sLock 加鎖;
  • 判斷 initializing 中存在當(dāng)前組件,說明存在循環(huán)依賴(這是因為遞歸初始化所依賴的組件時,會將 initializing 作為參數(shù)傳入,如果 initializing 中存在當(dāng)前組件,說明依賴關(guān)系形成回環(huán),如果不拋出異常,將形成無限遞歸);
  • 檢查當(dāng)前組件是否已初始化;
  • 記錄正在初始化;
  • 通過反射實例化 Initializer 接口實現(xiàn)類;
  • 遍歷所依賴的組件,如果所依賴的組件未初始化,遞歸調(diào)用doInitialize(...)執(zhí)行初始化;
  • 初始化當(dāng)前組件;
  • 移除正在初始化記錄;
  • 緩存初始化結(jié)果;

3、手動初始化源碼分析

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

  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<?>>()); 

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

前面有一個sLock沒有說嗎?其實它就是用來保證線程同步的鎖:

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

總結(jié)

App Startup 是 Jetpack 的新成員,是為了解決因 App 啟動時運行多個 ContentProvider 會增加 App 的啟動時間的問題;

使用了一個 InitializationProvider 管理多個依賴項,消除了每個庫單獨使用 ContentProvider 成本,減少初始化時間;

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

 

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

 

責(zé)任編輯:武曉燕 來源: Android開發(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操作對象

2022-01-14 12:28:18

架構(gòu)OpenFeign遠程

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

2021-09-16 06:44:04

Android進階流程

2014-07-15 17:17:31

AdapterAndroid

2021-09-15 07:31:33

Android窗口管理

2021-09-24 08:10:40

Java 語言 Java 基礎(chǔ)

2017-08-08 09:15:41

前端JavaScript頁面渲染

2021-02-17 11:25:33

前端JavaScriptthis

2021-10-26 17:52:52

Android插件化技術(shù)

2017-08-15 13:05:58

Serverless架構(gòu)開發(fā)運維

2021-10-10 13:31:14

Java負(fù)載均衡算法

2021-10-21 10:02:37

Java開發(fā)代碼

2024-03-12 00:00:00

Sora技術(shù)數(shù)據(jù)
點贊
收藏

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