Android性能優(yōu)化:那些不可忽略的繪制優(yōu)化


前言

  • Android開發(fā)中,性能優(yōu)化策略十分重要
  • 本文主要講解性能優(yōu)化中的繪制優(yōu)化,希望你們會(huì)喜歡。

目錄

示意圖

1. 影響的性能

繪制性能的好壞 主要影響 :Android應(yīng)用中的頁面顯示速度


2. 如何影響性能

繪制影響Android性能的實(shí)質(zhì):頁面的繪制時(shí)間

1個(gè)頁面通過遞歸 完成測(cè)量 & 繪制過程


3. 優(yōu)化思路

主要優(yōu)化方向是:

  1. 降低View.onDraw()的復(fù)雜度
  2. 避免過度繪制(Overdraw)

4. 具體優(yōu)化方案

  • 具體如下
示意圖
  • 下面,我將詳細(xì)分析每種優(yōu)化方案

4.1. 降低View.onDraw()的復(fù)雜度

4.1.1 onDraw()中不要?jiǎng)?chuàng)建新的局部對(duì)象

示意圖

4.1.2 避免onDraw()執(zhí)行大量 & 耗時(shí)操作

示意圖

4.2 避免過度繪制(Overdraw)

4.2.1 過度繪制的簡(jiǎn)介

示意圖

4.2.2 過度繪制的表現(xiàn)形式

過度繪制 會(huì)導(dǎo)致屏幕顯示的色塊不同,具體如下


示意圖

附:示例說明

示意圖

4.2.3 過度繪制的優(yōu)化原則

很多 過度繪制是難以避免的,如 上述實(shí)例的 文字 & 背景導(dǎo)致的過度繪制,只能盡可能避免過度繪制:

  1. 盡可能地控制 過度繪制的次數(shù) = 2 次(綠色)以下,藍(lán)色最理想
  2. 盡可能避免 過度繪制的粉色 & 紅色情況
  3. 不允許 3 次以上的過度繪制(淡紅色)面積 超過 屏幕大小的 1/4

4.2.4 優(yōu)化方案

  1. 移除默認(rèn)的 Window 背景
  2. 移除 控件中不必要的背景
  3. 減少布局文件的層級(jí)(嵌套)
  4. 自定義控件View優(yōu)化:使用 clipRect() 、 quickReject()

優(yōu)化方案1: 移除默認(rèn)的 Window 背景

  • 背景:一般應(yīng)用程序 默認(rèn) 繼承的主題 = windowBackground ,如默認(rèn)的 Light 主題:
<style name="Theme.Light">
    <item name="isLightTheme">true</item>
    <item name="windowBackground">@drawable/screen_background_selector_light</item>
    ...
</style>
  • 問題:一般情況下,該默認(rèn)的 Window 背景基本用不上:因背景都自定義設(shè)置
    若不移除,則導(dǎo)致所有界面都多 1 次繪制

  • 解決方案:移除默認(rèn)的 Window 背景

// 方式1:在應(yīng)用的主題中添加如下的一行屬性
    <item name="android:windowBackground">@android:color/transparent</item>
    <!-- 或者 -->
    <item name="android:windowBackground">@null</item>

// 方式2:在 BaseActivity 的 onCreate() 方法中使用下面的代碼移除
    getWindow().setBackgroundDrawable(null);
    <!-- 或者 -->
    getWindow().setBackgroundDrawableResource(android.R.color.transparent);

優(yōu)化方案2:移除 控件中不必要的背景

如2個(gè)常見場(chǎng)景:

  • 場(chǎng)景1:ListViewItem
    列表頁(ListView) 與 其內(nèi)子控件(Item)的背景相同 = 白色,故可移除子控件(Item)布局中的背景
示意圖
  • 場(chǎng)景2:ViewPagerFragment
    對(duì)于1個(gè)ViewPager + 多個(gè) Fragment 組成的首頁界面,若每個(gè)Fragment 都設(shè)有背景色,即 ViewPager 則無必要設(shè)置,可移除
示意圖

關(guān)于更多場(chǎng)景,可使用工具 Hierarchy View 查看,具體請(qǐng)看文章: 過渡繪制的使用工具:Hierarchy View

優(yōu)化方案3:減少布局文件的層級(jí)(減少不必要的嵌套)

  • 原理:減少不必要的嵌套 ->> UI層級(jí)少 ->> 過度繪制的可能性低
  • 優(yōu)化方式:使用布局標(biāo)簽<merge> & 合適選擇布局類型

具體請(qǐng)看文章:Android性能優(yōu)化:這是一份詳細(xì)的布局優(yōu)化 指南(含<include>、<Viewstub>、<merge>)

優(yōu)化方案4:自定義控件View優(yōu)化:使用 clipRect() 、 quickReject()

  • clipRect()
    1. 作用:給 Canvas 設(shè)置一個(gè)裁剪區(qū)域,只有在該區(qū)域內(nèi)才會(huì)被繪制,區(qū)域之外的都不繪制
    2. 實(shí)例說明:DrawerLayout 布局 = 左抽屜布局
示意圖
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTim
    // ...僅貼出關(guān)鍵代碼

        // 1. 遍歷 DrawerLayout 的 child view,拿到抽屜布局
        for (int i = 0; i < childCount; i++) {
            final View v = getChildAt(i);
            if (v == child || v.getVisibility() != VISIBLE
                    || !hasOpaqueBackground(v) || !isDrawerView(v)
                    || v.getHeight() < height) {
                continue;
            }
            // a. 若是左抽屜布局
            // 則取抽屜布局的右邊界作為裁剪區(qū)的左邊界、設(shè)置原主布局的裁剪區(qū)域,如上圖裁剪區(qū)域
            if (checkDrawerViewAbsoluteGravity(v, Gravity.LEFT)) {
                final int vright = v.getRight();
                if (vright > clipLeft) clipLeft = vright;
            // b. 若是右抽屜布局
            // 則取抽屜布局的左邊界作為裁剪區(qū)的右邊界、設(shè)置原主布局的裁剪區(qū)域
            } else {
                final int vleft = v.getLeft();
                if (vleft < clipRight) clipRight = vleft;
            }
        }
        // 2. 通過clipRect()設(shè)置原主布局的顯示范圍 = 裁剪區(qū)域,使其僅在上圖中的紅框區(qū)域(即不阻礙抽屜布局的區(qū)域)顯示
       // 從而避免過度繪制
        canvas.clipRect(clipLeft, 0, clipRight, getHeight());
    }                
}
  • quickreject()
    1. 作用:判斷和某個(gè)矩形相交
    2. 具體措施:若判斷與矩形相交,則可跳過相交的區(qū)域,從而減少過度繪制

4.3 其他優(yōu)化方案

示意圖

總結(jié)

示意圖

至此,關(guān)于繪制優(yōu)化的方案講解完畢。

5. 布局調(diào)優(yōu)工具

  • 背景
    盡管已經(jīng)注意到上述的優(yōu)化策略,但實(shí)際開發(fā)中難免還是會(huì)出現(xiàn)布局性能的問題
  • 解決方案
    使用 布局調(diào)優(yōu)工具

此處主要介紹 常用的:hierarchy viewer、Profile GPU Rendering、Systrace

5.1 Hierarchy Viewer

  • 簡(jiǎn)介
    Android Studio 提供的UI性能檢測(cè)工具。

  • 作用
    可視化獲得UI布局設(shè)計(jì)結(jié)構(gòu) & 各種屬性信息,幫助我們優(yōu)化布局設(shè)計(jì)

即 :方便查看Activity布局,各個(gè)View的屬性、布局測(cè)量-布局-繪制的時(shí)間

5.2 Profile GPU Rendering

  • 簡(jiǎn)介
    一個(gè) 圖形監(jiān)測(cè)工具

  • 作用
    渲染、繪制性能追蹤

能實(shí)時(shí)反應(yīng)當(dāng)前繪制的耗時(shí)

  • 具體使用
    橫軸 = 時(shí)間、縱軸 = 每幀的耗時(shí);隨著時(shí)間推移,從左到右的刷新呈現(xiàn)

提供一個(gè)標(biāo)準(zhǔn)的耗時(shí),如果高于標(biāo)準(zhǔn)耗時(shí),就表示當(dāng)前這一幀丟失

示意圖

更詳細(xì)使用請(qǐng)看: Profile GPU Rendering 使用指南

5.3 Systrace

  • 簡(jiǎn)介
    Android 4.1以上版本提供的性能數(shù)據(jù)采樣 & 分析工具
  • 作用
    檢測(cè) Android系統(tǒng)各個(gè)組件隨著時(shí)間的運(yùn)行狀態(tài) & 提供解決方案
  1. 收集 等運(yùn)行信息,從而幫助開發(fā)者更直觀地分析系統(tǒng)瓶頸,改進(jìn)性能
    檢測(cè)范圍包括:Android 關(guān)鍵子系統(tǒng)(如WindowManagerServiceFramework 部分關(guān)鍵模塊)、服務(wù)、View系統(tǒng)
  2. 功能包括:跟蹤系統(tǒng)的I/O 操作、內(nèi)核工作隊(duì)列、CPU 負(fù)載等,在 UI 顯示性能分析上提供很好的數(shù)據(jù),特別是在動(dòng)畫播放不流暢、渲染卡等問題上

6. 總結(jié)

  • 本文主要講解Android 性能優(yōu)化中的 繪制優(yōu)化
示意圖

請(qǐng)點(diǎn)贊!因?yàn)槟愕墓膭?lì)是我寫作的最大動(dòng)力!

相關(guān)文章閱讀
Android開發(fā):最全面、最易懂的Android屏幕適配解決方案
Android事件分發(fā)機(jī)制詳解:史上最全面、最易懂
Android開發(fā):史上最全的Android消息推送解決方案
Android開發(fā):最全面、最易懂的Webview詳解
Android開發(fā):JSON簡(jiǎn)介及最全面解析方法!
Android四大組件:Service服務(wù)史上最全面解析
Android四大組件:BroadcastReceiver史上最全面解析


歡迎關(guān)注Carson_Ho的簡(jiǎn)書!

不定期分享關(guān)于安卓開發(fā)的干貨,追求短、平、快,但卻不缺深度。

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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