Android啟動(dòng)優(yōu)化方案

背景

應(yīng)用啟動(dòng)時(shí)間是衡量APP用戶體驗(yàn)的第一道門(mén),一般情況下應(yīng)用啟動(dòng)時(shí)間在1秒以內(nèi),用戶會(huì)覺(jué)得響應(yīng)時(shí)間很快;1-3秒內(nèi)完成啟動(dòng),用戶會(huì)覺(jué)得啟動(dòng)速度還可以;超過(guò)3秒,用戶就會(huì)覺(jué)得很慢;超過(guò)5秒,用戶會(huì)直接放棄這個(gè)應(yīng)用。

應(yīng)用啟動(dòng)時(shí)間的定義

在Android系統(tǒng)中把啟動(dòng)分為冷啟動(dòng),熱啟動(dòng),溫啟動(dòng)。三者的過(guò)程各不相同,其中以冷啟動(dòng)過(guò)程最為繁瑣,時(shí)間消耗最長(zhǎng)。所以市面上所說(shuō)的啟動(dòng)優(yōu)化,一般都泛指冷啟動(dòng)的優(yōu)化。

什么是冷啟動(dòng)

冷啟動(dòng)就是在系統(tǒng)沒(méi)有任何該應(yīng)用信息的場(chǎng)景下啟動(dòng)應(yīng)用的行為。比如第一次安裝APP后,用戶手動(dòng)點(diǎn)擊APP圖標(biāo),然后啟動(dòng)應(yīng)用,這個(gè)過(guò)程就是一個(gè)標(biāo)準(zhǔn)的冷啟動(dòng)的過(guò)程。
那么在這場(chǎng)景之下,實(shí)際系統(tǒng)做了一些什么事情呢?
1.用戶點(diǎn)擊應(yīng)用圖標(biāo)
2.目標(biāo)應(yīng)用進(jìn)程調(diào)起
3.綁定應(yīng)用Application,并執(zhí)行生命周期
4.啟動(dòng)主Activity,并執(zhí)行生命周期,完成界面的測(cè)量計(jì)算繪制
5.用戶看到界面首幀畫(huà)面

優(yōu)化的方向

在第3步之前的行為都是系統(tǒng)行為,我們無(wú)法干涉,這段時(shí)間完全取決于手機(jī)的客觀性能。我們將從第三步開(kāi)始優(yōu)化,方向分為以下幾個(gè)方面:
1.Application的生命周期
2.主Activity的生命周期
3.主Activity界面的測(cè)量繪制優(yōu)化

優(yōu)化的角度

上面已經(jīng)確定了優(yōu)化的方向,那我們就從Application的生命周期方向開(kāi)始優(yōu)化。在實(shí)際項(xiàng)目中,我們會(huì)使用很多第三方庫(kù),而那些庫(kù)不約而同的都會(huì)要求讓你在Application的onCreate方法對(duì)他進(jìn)行初始化,再加上我們自己的業(yè)務(wù)需要也會(huì)在onCreate方法中添加邏輯,那么Application的onCreate方法不可避免的代碼臃腫。Java程序都是單線程的程序,即只有一個(gè)主線程,那我們的目標(biāo)就是不要堵塞onCreate方法,有以下幾個(gè)角度來(lái)思考
1.邏輯異步
2.邏輯延遲
3.邏輯懶加載

邏輯異步

什么是邏輯異步?就是用多線程去替代之前單個(gè)主線程的工作,盡量保證讓onCreate流暢不被堵塞。那么我們?cè)撛趺丛O(shè)計(jì)呢?設(shè)計(jì)的思路我們可以參考Gradle,將邏輯Task化。
1.將原本冗余的邏輯代碼區(qū)分開(kāi)來(lái),抽象成一個(gè)Task
2.確定Task是否必須執(zhí)行在主線程,是否必須在onCreate中執(zhí)行完,執(zhí)行上下是否存在依賴關(guān)系
3.設(shè)計(jì)一個(gè)Task分發(fā)管理類,負(fù)責(zé)將所有Task集合后生成一個(gè)有向無(wú)環(huán)圖,這點(diǎn)也是參考Gradle的執(zhí)行思路

public interface ITask{
          /*是否必須在UI線程中執(zhí)行*/
          public boolean isRunOnUIThread()
          /*依賴的其他任務(wù)*/
          public ITask dependOn()
          /*是否必須在onCreate函數(shù)中執(zhí)行完成*/
          public boolean isNeedWait()
}

上面是Task接口的粗略抽象定義,實(shí)際場(chǎng)景下還可以根據(jù)業(yè)務(wù)補(bǔ)充。最后在Application中的onCreate方法中將會(huì)是一段非常簡(jiǎn)潔的代碼,這樣的代碼也易于維護(hù)閱讀。類似下面這樣的偽代碼

...
pulbic void onCreate(){
         new TaskManager().addTask(new ATask())
                          .addTask(new BTask())
                          .addTask(new CTask())
                          ...
                          .addTask(new ETask())
                          .start();              
}
...

邏輯延遲

什么是邏輯延遲?就是將一些優(yōu)先級(jí)不是非常高的代碼和邏輯延遲執(zhí)行,不堵塞生命周期的方法。一般的方案可以是使用Handler延遲代碼執(zhí)行,但是這個(gè)方案是有缺陷的,有可能會(huì)影響用戶操作卡頓。比如代碼延遲1000ms執(zhí)行,但是如果這個(gè)時(shí)候用戶正好在滑動(dòng)手機(jī)操作,再加上延遲的任務(wù)比較復(fù)雜,這時(shí)用戶操作任務(wù)和延遲執(zhí)行任務(wù)就會(huì)同時(shí)執(zhí)行搶占cpu,然后一部分性能不好的手機(jī)就會(huì)有卡頓現(xiàn)象。解決方案是什么?
IdleHandler:當(dāng)Handler空閑的時(shí)候才會(huì)被調(diào)用名,如果返回true,則會(huì)一直執(zhí)行,如果返回false,執(zhí)行完一次后就會(huì)被移除消息隊(duì)列。比如,我們可以將從服務(wù)器獲取推送Token的任務(wù)放在延遲Handler中執(zhí)行。

public class DelayHandler implements MessageQueue.IdleHandler{
  private Context mContext

  public DelayHandler(Context context){
      mContext = context.getApplicationContext();
  }

  public boolean queueIdle(){
    //doSomething
    return false;
  }
}
Looper.myQueue().addIdleHandler(new DelayHandler(this))

上面的代碼只是最簡(jiǎn)單的運(yùn)行。

懶加載

由于懶加載是有業(yè)務(wù)的強(qiáng)相關(guān)性,這里就舉一個(gè)例子,很多app會(huì)在Application的靜態(tài)代碼塊中把所有動(dòng)態(tài)庫(kù)都加上,這就有待商榷了,完全可以在具體的業(yè)務(wù)代碼模塊使用時(shí)再加載動(dòng)態(tài)庫(kù)。這只是很小的一個(gè)方面,具體問(wèn)題具體分析。

總結(jié)

邏輯異步,邏輯延遲,懶加載,這是啟動(dòng)優(yōu)化的方向。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容