天天看點

Android應用啟動優化:一種DelayLoad的實作和原理(轉)

在逛文章的時候看到的一個不錯的文章,轉給大家,原文位址:http://androidperformance.com/2015/11/18/android-app-lunch-optimize-delay-load.html

應用啟動優化概述

在 android 開發中,應用啟動速度是一個非常重要的點,應用啟動優化也是一個非常重要的過程.對于應用啟動優化,其實核心思想就是在啟動過程中少做事情,具體實踐的時候無非就是下面幾種:

1.異步加載

2.延時加載

3.懶加載

不用一一去解釋,做過啟動優化的估計都使用過,本篇文章将詳細講解一下一種延時加載的實作以及其原理.

其實這種加載的實作是非常簡單的,但是其中的原理可能比較複雜,還涉及到looper/handler/messagequeue/vsync等.以及其中碰到的一些問題,還會有一些我自己額外的思考.

優化後的delayload的實作

一提到delayload,大家可能第一時間想到的就是在 oncreate 裡面調用 handler.postdelayed方法, 将需要 delay 加載的東西放到這裡面去初始化, 這個也是一個比較友善的方法. delay一段時間再去執行,這時候應用已經加載完成,界面已經顯示出來了, 不過這個方法有一個緻命的問題: 延遲多久?

大家都知道,在 android 的高端機型上,應用的啟動是非常快的 , 這時候隻需要 delay 很短的時間就可以了, 但是在低端機型上,應用的啟動就沒有那麼快了,而且現在應用為了相容舊的機型,往往需要 delay 較長的時間,這樣帶來體驗上的差異是很明顯的.

這裡先說優化方案:

1。首先 , 建立 handler 和 runnable 對象, 其中 runnable 對象的 run方法裡面去更新 ui 線程.

2.在主 activity 的 oncreate 中加入下面的代碼

其實實作的話非常簡單,我們來對比一下三種方案的效果.

2. 三種寫法的差異對比

為了驗證我們優化的 delayload的效果,我們寫了一個簡單的app , 這個 app 中包含三張不同大小的圖檔,每張圖檔下面都會有一個 textview , 來标記圖檔的顯示高度和寬度. mainactivity的代碼如下:

我們需要關注幾點:

updatetext 這個函數是什麼時候被執行的?

app 啟動後,三個圖檔的長寬是否可以被正确地顯示出來?

是否有 delay load 的效果?

2.1 第一種寫法

1.updatetext執行的時機?

下面是第一種寫法的trace圖:

Android應用啟動優化:一種DelayLoad的實作和原理(轉)

可以看到 updatetext 是在 activity 的 oncreate/onstart/onresume三個回調執行完成後才去執行的.

2.圖檔的寬高是否正确顯示?

Android應用啟動優化:一種DelayLoad的實作和原理(轉)

從圖檔看一看到,寬高并沒有顯示. 這是為什麼呢? 這個問題就要從activity 的 oncreate/onstart/onresume三個回調說起了. 其實activity 的 oncreate/onstart/onresume三個回調中,并沒有執行measure和layout操作, 這個是在後面的performtraversals中才執行的. 是以在這之前寬高都是0.

3.是否有 delay load 的效果?

并沒有. 因為我們知道, 應用啟動的時候,要等兩次 performtraversals 都執行完成之後才會顯示第一幀, 而 updatetext 這個方法在第一個 performtraversals 執行之前就執行了. 是以 updatetext 方法的執行時間是算在應用啟動的時間裡面的.

2.2 第二種寫法

第二種寫法我們delay了300ms .我們來看一下表現.

Android應用啟動優化:一種DelayLoad的實作和原理(轉)

可以看到,這種寫法的話,updatetext是在兩個performtraversals 執行完成之後(這時候 app 的第一幀才顯示出來)才去執行的, 執行完成之後又調用了一次 performtraversals 将 textview 的内容進行更新.

Android應用啟動優化:一種DelayLoad的實作和原理(轉)

從上圖可以看到,圖檔的寬高是正确顯示了出來. 原因上面已經說了,measure/layout執行完成後,寬高的資料就可以擷取了.

不一定,取決于 delay的時長.

從前面的 trace 圖上我們可以看到 , updatetext 方法由于 delay 了300ms, 是以在應用第一幀顯示出來170ms之後, 圖檔的文字資訊才進行了更新. 這個是有 delay load 的效果的.

但是這裡隻是一個簡單的textview的更新, 如果是較大子產品的加載 , 使用者視覺上會有很明顯的 “ 空白->内容填充” 這個過程, 或者會附加”閃一下”特效…這顯然是我們不想看到的.

有人會說:可以把delay的時間減小一點嘛,這樣就不會閃了. 話是這麼說,但是由于 android 機器的多元性(其實就是有很多高端機器,也有很多低端機器) , 在這個機子上300ms的延遲算是快,在另外一個機子上300ms算是很慢.

我們将delay時間調整為50ms, 其trace圖如下:

第二種寫法:delay 50ms

Android應用啟動優化:一種DelayLoad的實作和原理(轉)

可以看到,updatetext 方法在第一個 performtraversals 之後就執行了,是以也沒有 delay load 的效果(雖然寬高是正确顯示了,因為在第一個 performtraversals 方法中就執行了layout和measure).

2.3 第三種寫法

經過前兩個方法 , 我們就會想, 如果能不使用delay方法, updatetext 方法能在 第二個performtraversals 方法執行完成後(即app第一幀在螢幕上顯示),馬上就去執行,那麼即起到了 delay load的作用,又可以正确顯示圖檔的寬高.

第三種寫法就是這個效果:

Android應用啟動優化:一種DelayLoad的實作和原理(轉)

可以看到這種寫法. updatetext 在第二個 performtraversals 方法執行完成後馬上就執行了, 然後下一個 vsync 信号來了之後, textview就更新了.

當然是正确顯示的.如圖:

Android應用啟動優化:一種DelayLoad的實作和原理(轉)

3. 一些思考

關于優化的 delay load 的實作,從代碼層面來看其實是非常簡單的.其帶來的效果也是很贊的.

但是實作之後我們還需要思考一下,為何這麼做就可以實作這種功能呢?很顯然要回答這個問題,我們需要知道更底層的一些東西.這個還涉及到 handler/message/messagequeue/looper/vsync/viewrootimpl等知識. 往大裡說應該還涉及到ams/wms等.由于涉及到的東西比較多,我就不在這一篇裡面闡述了, 下一篇文章将會從從原理上講解一下為何優化的 delay load 會起作用.

繼續閱讀