是什么拖慢了你的 App 啟動?干掉它!
你的應用,啟動夠快嗎?
App 啟動時,我們通常會執(zhí)行很多既定的任務,比如各種 SDK 的初始化、各種數(shù)據(jù)的初始化等。這必將拖慢 App 的啟動速度。
啟動速度,一直在我們的 App 優(yōu)化清單上,而在 11 月舉辦的 Android 綠色聯(lián)盟開發(fā)者大會上,推出了應用體驗標準。對應用的兼容性、穩(wěn)定性、性能、功能和安全,都做了詳細的定義。
其中啟動速度做了更細致的要求,冷啟動 < 1s,熱啟動 < 0.5s。這當然是最理想的情況,具體還有外部因素的影響,例如手機配置。
啟動時初始化的代碼,勢必會拖慢 App 的啟動速度,但是不等待這些任務初始化完成呢,可能又會造成功能的缺失,而有時候不同任務還存在時序依賴的關系,要求我們先執(zhí)行 A 任務,再執(zhí)行 B 任務。
每次都特殊處理會增加復雜度,我們需要一套通用的解決方案。
這里給大家推薦一個 Alibaba 在 Github 上開源的一個 Alpha 的庫。它是一個基于 PERT 圖構建的 Android 異步啟動框架。
Alibaba Alpha
PERT 圖又稱為“計劃評審技術”,它采用網(wǎng)絡圖來描述一個項目的任務網(wǎng)絡。不僅可以表達任務與任務之間的關系,不同的任務之間還可以有各種子任務。
Alpha 就是基于 PERT 圖設計思想,它簡單、高效、功能完整。利用 Alpha 在應用啟動的時候,讓這些任務并發(fā)處理,從而達到提高啟動速度的目的。并且可以保證他們執(zhí)行順序的正確性。
Alpha 在使用時,只需要定義好自己的 Task,并描述它依賴的 Task,再將他們添加到 Project 中??蚣軙詣硬l(fā)有序地執(zhí)行這些 Task,***將執(zhí)行結果拋出來。
為了支持 Android 應用的多進程,Alpha 支持為不同進程配置不同的啟動模式。
Alpha 的接入非常簡單,它支持 Java 代碼和配置文件兩種方式來構建一個啟動流程。
接入 Alpha
Gradle 依賴
- compile 'com.alibaba.android:alpha:1.0.0.1@jar'
使用 Gradle 可能會導致失敗,這里可以考慮通過源碼引入的方式。
使用指南
1. 實現(xiàn)自己的 Task 類
在 Alpha 中,任務都是一個個 Task。定義一個 Task,并在 run() 方法中實現(xiàn)該 Task 需要做的事情。
- public class SampleTask extends Task{
- public SampleTask() {
- super("SampleTask");
- }
- @Override
- public void run() {
- //do something, print a msg for example.
- Log.d(TAG, "run SampleTask");
- }
- }
Task 默認是通過異步的方式在子線程中執(zhí)行,如果這個 Task 需要在主線程中執(zhí)行,可以在構造函數(shù)中指定。
- /**
- * 構造{@code Task}對象。
- *
- * @param name {@code Task}名字
- * @param isInUiThread 是否在UI線程執(zhí)行,true表示在UI線程執(zhí)行,false表示在非UI線程執(zhí)行,默認在非UI線程執(zhí)行。
- * <strong>注意:如果在UI線程執(zhí)行,則不能再使用{@link AlphaManager#waitUntilFinish()},否則會造成死鎖。</strong>
- */
- public Task(String name, boolean isInUiThread) {
- mName = name;
- mIsInUiThread = isInUiThread;
- }
2. 將 Task 組合成一個完整的 Project
可以用 Task.ProjectBuilder 依據(jù)各 Task 之間的依賴關系,將這些 Task 構建成一個完整的 Project。
- private Task createCommonTaskGroup() {
- Task a = new TaskA();
- Task b = new TaskB();
- Task c = new TaskC();
- Task d = new TaskD();
- Task e = new TaskE();
- Project.Builder builder = new Project.Builder();
- builder.add(a);
- builder.add(b).after(a);
- builder.add(c).after(a);
- builder.add(d).after(b, c);
- builder.add(e).after(a);
- Project group = builder.create();
- return group;
- }
ProjectBuilder 生成的 Project 本身又可以作為一個 Task 嵌入到另一個 Project 中。
- private Task createCommonTaskGroup() {
- Task a = new TaskA();
- Task b = new TaskB();
- Task c = new TaskC();
- Task d = new TaskD();
- Task e = new TaskE();
- Project.Builder builder = new Project.Builder();
- builder.add(a);
- builder.add(b).after(a);
- builder.add(c).after(a);
- builder.add(d).after(b, c);
- builder.add(e).after(a);
- Project group = builder.create();
- return group;
- }
- private void createProject() {
- Task group = createCommonTaskGroup();
- Task f = new TaskF();
- Project.Builder builder = new Project.Builder();
- builder.add(group);
- builder.add(f);
- Project project = builder.create();
- }
3. 監(jiān)聽 Task 執(zhí)行結束
可以通過 addOnTaskFinishListener() 監(jiān)聽 Task 的執(zhí)行結束。
- /**
- * <p>增加{@code Task}執(zhí)行結束的監(jiān)聽,當該{@code Task}執(zhí)行結束時,會回調
- * {@link Task.OnTaskFinishListener#onTaskFinish(String)}。</p>
- * <strong>注意:</strong>回調函數(shù)在{@code Task}所在線程中回調,注意線程安全。
- *
- * @param listener 監(jiān)聽{@code Task}執(zhí)行結束的{@code listener}
- */
- public void addOnTaskFinishListener(OnTaskFinishListener listener) {
- if (!mTaskFinishListeners.contains(listener)) {
- mTaskFinishListeners.add(listener);
- }
- }
4. 為構建完成的 Project 配置對應的進程
通過 addProject(),將 Project 配置到對應的進程中。
- AlphaManager.getInstance(mContext)
- .addProject(project);
5. 執(zhí)行啟動流程
***只需要調用一句 start() 方法,就可以執(zhí)行這個完整的流程了。
- AlphaManager.getInstance(mContext)
- .start();
Alpha 還提供了配置文件的方式來配置 Task 的關系,但是我不準備再詳細介紹了,反正我不會這么用,有興趣還是去查詢 README 文件吧。
小結
利用 Alpha 我們可以有效的管理啟動時初始化的一些任務,從而達到優(yōu)化啟動速度的目的。
Alpha 是 Alibaba 開源的,現(xiàn)在我還不確定用在了那些阿里系的商業(yè)項目上,不過從源碼的角度來看,沒有大坑,而且各自文檔也很齊全,如果有這方面的需求,可以嘗試使用。
【本文為51CTO專欄作者“張旸”的原創(chuàng)稿件,轉載請通過微信公眾號聯(lián)系作者獲取授權】