溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android勇闖高階性能優(yōu)化之如何實(shí)現(xiàn)啟動優(yōu)化

發(fā)布時間:2021-10-25 11:16:35 來源:億速云 閱讀:99 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“Android勇闖高階性能優(yōu)化之如何實(shí)現(xiàn)啟動優(yōu)化”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Android勇闖高階性能優(yōu)化之如何實(shí)現(xiàn)啟動優(yōu)化”吧!

? 啟動內(nèi)部機(jī)制

應(yīng)用有三種啟動狀態(tài):

  • 冷啟動;

  • 溫啟動;

  • 熱啟動。

? 冷啟動

冷啟動是指應(yīng)用從頭開始:冷啟動發(fā)生在設(shè)備啟動后第一次啟動應(yīng)用程序 (Zygote>fork>app) ,或系統(tǒng)關(guān)閉應(yīng)用程序后。

在冷啟動開始時,系統(tǒng)有三個任務(wù)。 這些任務(wù)是:

  • 加載和啟動應(yīng)用程序。

  • 啟動后立即顯示應(yīng)用程序的空白啟動頁面。

  • 創(chuàng)建應(yīng)用程序進(jìn)程。

一旦系統(tǒng)創(chuàng)建了應(yīng)用程序進(jìn)程,應(yīng)用程序進(jìn)程就負(fù)責(zé)接下來的階段:

  • 創(chuàng)建應(yīng)用的實(shí)體。

  • 啟動主線程。

  • 創(chuàng)建主頁面。

  • 繪制頁面上的View。

  • 布局頁面。

  • 執(zhí)行首次的繪制。

如下圖:

Android勇闖高階性能優(yōu)化之如何實(shí)現(xiàn)啟動優(yōu)化

  • Displayed Time:初始顯示時間

  • reportFullyDrawn():完全顯示的時間

注意:在創(chuàng)建 Application 和創(chuàng)建 Activity 期間可能會出現(xiàn)性能問題。

? 創(chuàng)建 Application

當(dāng)應(yīng)用程序啟動時,空白啟動頁面保留在屏幕上,直到系統(tǒng)首次完成應(yīng)用程序的繪制。

如果你重寫了Application.onCreate(),系統(tǒng)將調(diào)用Application 上的onCreate()方法。之后,應(yīng)用程序生成主線程,也稱為UI線程,并將創(chuàng)建主Activity的任務(wù)交給它。

? 創(chuàng)建Activity

應(yīng)用進(jìn)程創(chuàng)建你的Activity后,Activity會執(zhí)行以下操作:

  • 初始化值。

  • 調(diào)用構(gòu)造函數(shù)。

  • 調(diào)用 Activity 當(dāng)前生命周期狀態(tài)的回調(diào)方法,如 Activity.onCreate()。

注意:onCreate() 方法對加載時間的影響最大,因?yàn)樗鼒?zhí)行開銷最高的工作:加載UI的布局和渲染,以及初始化Activity運(yùn)行所需的對象。

? 熱啟動

熱啟動時,系統(tǒng)將應(yīng)用從后臺拉回前臺,應(yīng)用程序的 Activity 在內(nèi)存中沒有被銷毀,那么應(yīng)用程序可以避免重復(fù)對象初始化,UI的布局和渲染。

如果 Activity 被銷毀則需要重新創(chuàng)建。

和冷啟動的區(qū)別: 不需要創(chuàng)建 Application。

? 溫啟動

溫啟動介于冷啟動和熱啟動中間吧。例如:

用戶按返回鍵退出應(yīng)用,然后重新啟動。進(jìn)程可能還沒有被殺死,但應(yīng)用必須通過調(diào)用onCreate()重新創(chuàng)建 Activity。

系統(tǒng)回收了應(yīng)用的內(nèi)存,然后用戶重新運(yùn)行應(yīng)用。應(yīng)用進(jìn)程和Activity都需要重新啟動。

咱們看看他們共同消耗多長時間。

? 查詢的啟動時間

? 初始顯示時間(Time to initial display)

在 Android 4.4(API 級別 19)及更高版本中,logcat 包含一個輸出行,其中包含一個名為 Displayed 的值。 此值表示啟動流程和完成在屏幕上繪制相應(yīng)活動之間經(jīng)過的時間量。 經(jīng)過的時間包含以下事件序列:

  • 啟動進(jìn)程。

  • 初始化對象。

  • 創(chuàng)建并初始化Activity。

  • 加載布局。

  • 第一次繪制你的應(yīng)用程序。

注意這里查看日志需要如下操作:

Android勇闖高階性能優(yōu)化之如何實(shí)現(xiàn)啟動優(yōu)化

報告的日志行類,如下圖:

Android勇闖高階性能優(yōu)化之如何實(shí)現(xiàn)啟動優(yōu)化

//冷啟動
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +1s355ms
//溫啟動(進(jìn)程被殺死)
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;

然后我們在后臺殺死進(jìn)程,再次啟動應(yīng)用;

第二個時間,溫啟動時間:+1s46ms;

這里咱們在后臺殺死進(jìn)程所以:應(yīng)用進(jìn)程和Activity需要重新啟動。

第三個時間:熱啟動時間:+289ms 和 +253ms;

按返回鍵,僅退出activity。所以耗時比較短。

當(dāng)然整體看這個應(yīng)用開啟時間并不長,因?yàn)?Demo 的 Application 和 Activity 都沒有進(jìn)行太多的操作。

? 完全顯示時間(Time to full display)

你可以使用 reportFullyDrawn() 方法來測量應(yīng)用程序啟動和所有資源和視圖層次結(jié)構(gòu)的完整顯示之間經(jīng)過的時間。在應(yīng)用程序執(zhí)行延遲加載的情況下,這可能很有價值。在延遲加載中,應(yīng)用程序不會阻止窗口的初始繪制,而是異步加載資源并更新視圖層次結(jié)構(gòu)。

這里我在Activity.onCreate()中加了個工作線程。并在里面調(diào)用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();
}

報告的日志行類,如下圖:

Android勇闖高階性能優(yōu)化之如何實(shí)現(xiàn)啟動優(yōu)化

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

圖例講解:

然后你會發(fā)現(xiàn)界面出來好一會才打這個日志??吹竭@里我覺得好多人已經(jīng)知道怎么去優(yōu)化啟動速度了。

? 性能遲緩分析

看到上面的實(shí)驗(yàn)其實(shí)三種啟動情況,受我們影響的方面在于 application 和 activity 。

? Application 初始化

當(dāng)你的代碼覆蓋 Application 對象并在初始化該對象時執(zhí)行繁重的工作或復(fù)雜的邏輯時,啟動性能可能會受到影響。 產(chǎn)生的原因包括:

  • 應(yīng)用程序的初始o(jì)nCreate()函數(shù)。如:執(zhí)行了不需要立即執(zhí)行的初始化。

  • 應(yīng)用程序初始化的任何全局單例對象。如:一些不必要的對象。

  • 可能發(fā)生的任何磁盤I/O、反序列化或緊密循環(huán)。

解決方案

無論問題在于不必要的初始化還是磁盤I/O,解決方案都是延遲初始化。換句話說,你應(yīng)該只初始化立即需要的對象。不要創(chuàng)建全局靜態(tài)對象,而是轉(zhuǎn)向單例模式,應(yīng)用程序只在第一次需要時初始化對象。

此外,考慮使用依賴注入框架(如Hilt)

? Activity初始化

活動創(chuàng)建通常需要大量高開銷工作。 通常,有機(jī)會優(yōu)化這項(xiàng)工作以實(shí)現(xiàn)性能改進(jìn)。

產(chǎn)生的原因包括:

  • 加載大型或復(fù)雜的布局。

  • 阻止在磁盤或網(wǎng)絡(luò) I/O 上繪制屏幕。

  • 加載和解碼Bitmap。

  • VectorDrawable 對象。

  • Activity 初始化任何全局單例對象。

  • 所有資源初始化。

解決方案如下。

? 布局優(yōu)化
  • 通過減少冗余或嵌套布局來扁平化視圖層次結(jié)構(gòu)。

  • 布局復(fù)用(< include/>和 < merge/> )

  • 使用ViewStub,不加載在啟動期間不需要可見的 UI 部分。

? 代碼優(yōu)化
  • 不必要的初始化還是磁盤I/O,延遲初始化

  • 資源初始化分類,以便應(yīng)用程序可以在不同的線程上延遲執(zhí)行。

  • 動態(tài)加載資源和Bitmap

關(guān)于這兩塊的優(yōu)化后續(xù)會有單獨(dú)的文章去寫。

? 阻塞實(shí)驗(yàn)

? Application 阻塞 2秒, Activity 阻塞 2秒

? SccApp.class
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();
        }
    }
}
? MainActivity.class
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
//溫啟動(進(jìn)程被殺死)
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

? 將Appliacation 和Activity阻塞的2秒都放在工作線程去操作

這個就是把代碼放在如下代碼中執(zhí)行即可,就不全部貼出來了。

new Thread(new Runnable() {
            @Override
            public void run() {
                ...
            }
        }).start();

運(yùn)行結(jié)果如下:

//冷啟動
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +1s227ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s957ms
//溫啟動(進(jìn)程被殺死)
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

? APP 啟動黑/白屏

Android 應(yīng)用啟動時,尤其是大型應(yīng)用, 經(jīng)常出現(xiàn)幾秒鐘的黑屏或白屏,黑屏或白屏取決于主界面 Activity 的主題風(fēng)格。

? 優(yōu)雅的解決黑白屛

Android 應(yīng)用啟動時很多大型應(yīng)用都會有一個廣告(圖片及視頻)頁或閃屏頁(2-3S)。這并不是開發(fā)者想要放上去的,而是為了避免上述啟動白屏導(dǎo)致用戶體很差。當(dāng)然你可以珍惜這2-3秒做一個異步加載或者請求。

寫到這里。應(yīng)用啟動模式、啟動時間、啟動速度優(yōu)化算是完事了。當(dāng)然后面如果有更好的優(yōu)化方案還會繼續(xù)補(bǔ)充。

到此,相信大家對“Android勇闖高階性能優(yōu)化之如何實(shí)現(xiàn)啟動優(yōu)化”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI