您好,登錄后才能下訂單哦!
本篇內容主要講解“Android勇闖高階性能優化之如何實現啟動優化”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Android勇闖高階性能優化之如何實現啟動優化”吧!
應用有三種啟動狀態:
冷啟動;
溫啟動;
熱啟動。
冷啟動是指應用從頭開始:冷啟動發生在設備啟動后第一次啟動應用程序 (Zygote>fork>app) ,或系統關閉應用程序后。
在冷啟動開始時,系統有三個任務。 這些任務是:
加載和啟動應用程序。
啟動后立即顯示應用程序的空白啟動頁面。
創建應用程序進程。
一旦系統創建了應用程序進程,應用程序進程就負責接下來的階段:
創建應用的實體。
啟動主線程。
創建主頁面。
繪制頁面上的View。
布局頁面。
執行首次的繪制。
如下圖:
Displayed Time:初始顯示時間
reportFullyDrawn():完全顯示的時間
注意:在創建 Application 和創建 Activity 期間可能會出現性能問題。
當應用程序啟動時,空白啟動頁面保留在屏幕上,直到系統首次完成應用程序的繪制。
如果你重寫了Application.onCreate(),系統將調用Application 上的onCreate()方法。之后,應用程序生成主線程,也稱為UI線程,并將創建主Activity的任務交給它。
應用進程創建你的Activity后,Activity會執行以下操作:
初始化值。
調用構造函數。
調用 Activity 當前生命周期狀態的回調方法,如 Activity.onCreate()。
注意:onCreate() 方法對加載時間的影響最大,因為它執行開銷最高的工作:加載UI的布局和渲染,以及初始化Activity運行所需的對象。
熱啟動時,系統將應用從后臺拉回前臺,應用程序的 Activity 在內存中沒有被銷毀,那么應用程序可以避免重復對象初始化,UI的布局和渲染。
如果 Activity 被銷毀則需要重新創建。
和冷啟動的區別: 不需要創建 Application。
溫啟動介于冷啟動和熱啟動中間吧。例如:
用戶按返回鍵退出應用,然后重新啟動。進程可能還沒有被殺死,但應用必須通過調用onCreate()重新創建 Activity。
系統回收了應用的內存,然后用戶重新運行應用。應用進程和Activity都需要重新啟動。
咱們看看他們共同消耗多長時間。
在 Android 4.4(API 級別 19)及更高版本中,logcat 包含一個輸出行,其中包含一個名為 Displayed 的值。 此值表示啟動流程和完成在屏幕上繪制相應活動之間經過的時間量。 經過的時間包含以下事件序列:
啟動進程。
初始化對象。
創建并初始化Activity。
加載布局。
第一次繪制你的應用程序。
注意這里查看日志需要如下操作:
報告的日志行類,如下圖:
//冷啟動
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +1s355ms
//溫啟動(進程被殺死)
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +1s46ms
//熱啟動
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +289ms
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +253ms
圖例講解:
第一個時間,冷啟動時間:+1s355ms;
然后我們在后臺殺死進程,再次啟動應用;
第二個時間,溫啟動時間:+1s46ms;
這里咱們在后臺殺死進程所以:應用進程和Activity需要重新啟動。
第三個時間:熱啟動時間:+289ms 和 +253ms;
按返回鍵,僅退出activity。所以耗時比較短。
當然整體看這個應用開啟時間并不長,因為 Demo 的 Application 和 Activity 都沒有進行太多的操作。
你可以使用 reportFullyDrawn() 方法來測量應用程序啟動和所有資源和視圖層次結構的完整顯示之間經過的時間。在應用程序執行延遲加載的情況下,這可能很有價值。在延遲加載中,應用程序不會阻止窗口的初始繪制,而是異步加載資源并更新視圖層次結構。
這里我在Activity.onCreate()中加了個工作線程。并在里面調用reportFullyDrawn() 方法。代碼如下:
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e(this.getClass().getName(), "onCreate"); setContentView(R.layout.activity_main); ... new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); reportFullyDrawn(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); }
報告的日志行類,如下圖:
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s970ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s836ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s107ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s149ms
圖例講解:
然后你會發現界面出來好一會才打這個日志。看到這里我覺得好多人已經知道怎么去優化啟動速度了。
看到上面的實驗其實三種啟動情況,受我們影響的方面在于 application 和 activity 。
當你的代碼覆蓋 Application 對象并在初始化該對象時執行繁重的工作或復雜的邏輯時,啟動性能可能會受到影響。 產生的原因包括:
應用程序的初始onCreate()函數。如:執行了不需要立即執行的初始化。
應用程序初始化的任何全局單例對象。如:一些不必要的對象。
可能發生的任何磁盤I/O、反序列化或緊密循環。
解決方案
無論問題在于不必要的初始化還是磁盤I/O,解決方案都是延遲初始化。換句話說,你應該只初始化立即需要的對象。不要創建全局靜態對象,而是轉向單例模式,應用程序只在第一次需要時初始化對象。
此外,考慮使用依賴注入框架(如Hilt)
活動創建通常需要大量高開銷工作。 通常,有機會優化這項工作以實現性能改進。
產生的原因包括:
加載大型或復雜的布局。
阻止在磁盤或網絡 I/O 上繪制屏幕。
加載和解碼Bitmap。
VectorDrawable 對象。
Activity 初始化任何全局單例對象。
所有資源初始化。
解決方案如下。
通過減少冗余或嵌套布局來扁平化視圖層次結構。
布局復用(< include/>和 < merge/> )
使用ViewStub,不加載在啟動期間不需要可見的 UI 部分。
不必要的初始化還是磁盤I/O,延遲初始化
資源初始化分類,以便應用程序可以在不同的線程上延遲執行。
動態加載資源和Bitmap
關于這兩塊的優化后續會有單獨的文章去寫。
public class SccApp extends Application { @RequiresApi(api = Build.VERSION_CODES.P) @Override public void onCreate() { super.onCreate(); String name = getProcessName(); MLog.e("ProcessName:"+name); getProcessName("com.scc.demo"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }
public class MainActivity extends ActivityBase implements View.OnClickListener { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e(this.getClass().getName(), "onCreate"); setContentView(R.layout.activity_main); ... try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); reportFullyDrawn(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } }
報告的日志,如下:
//冷啟動
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +5s458ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +8s121ms
//溫啟動(進程被殺死)
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +5s227ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +7s935ms
//熱啟動
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +2s304ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +5s189ms
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +2s322ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +5s169ms
這個就是把代碼放在如下代碼中執行即可,就不全部貼出來了。
new Thread(new Runnable() { @Override public void run() { ... } }).start();
運行結果如下:
//冷啟動
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +1s227ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s957ms
//溫啟動(進程被殺死)
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +1s83ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s828ms
//熱啟動
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +324ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s169ms
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +358ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s207ms
Android 應用啟動時,尤其是大型應用, 經常出現幾秒鐘的黑屏或白屏,黑屏或白屏取決于主界面 Activity 的主題風格。
Android 應用啟動時很多大型應用都會有一個廣告(圖片及視頻)頁或閃屏頁(2-3S)。這并不是開發者想要放上去的,而是為了避免上述啟動白屏導致用戶體很差。當然你可以珍惜這2-3秒做一個異步加載或者請求。
寫到這里。應用啟動模式、啟動時間、啟動速度優化算是完事了。當然后面如果有更好的優化方案還會繼續補充。
到此,相信大家對“Android勇闖高階性能優化之如何實現啟動優化”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。