Android繪製優化(二)佈局優化

来源:https://www.cnblogs.com/ganchuanpu/archive/2018/07/16/9316302.html
-Advertisement-
Play Games

前言 我們知道一個界面的測量和繪製是通過遞歸來完成的,減少佈局的層數就會減少測量和繪製的時間,從而性能就會得到提升。當然這隻是佈局優化的一方面,那麼如何來進行佈局的分析和優化呢?本篇文章會給你一個滿意的答案。 1.佈局優化工具 在講到如何去佈局優化前,我們先來學習兩種佈局優化的工具。 1.1 Hie ...


前言

我們知道一個界面的測量和繪製是通過遞歸來完成的,減少佈局的層數就會減少測量和繪製的時間,從而性能就會得到提升。當然這隻是佈局優化的一方面,那麼如何來進行佈局的分析和優化呢?本篇文章會給你一個滿意的答案。

1.佈局優化工具

在講到如何去佈局優化前,我們先來學習兩種佈局優化的工具。

1.1 Hierarchy Viewer

Hierarchy Viewer是Android SDK自帶的可視化的調試工具,用來檢查佈局嵌套和繪製的時間。需要註意的是在在Android的官方文檔中提到:出於安全考慮,Hierarchy Viewer只能連接Android開發版手機或是模擬器。
首先我們在Android Studio中選擇Tools->Android->Android Device Monitor,在Android Device Monitor中選擇Hierarchy Viewer ,如下圖所示:


選擇Hierarchy Viewer後會進出Hierarchy Viewer視窗,如下圖所示。

Hierarchy Viewer中有4個四個子視窗,它們的的作用為:

  • Windows:當前設備所有界面列表。
  • Tree View:將當前Activity的所有View的層次按照高層到低層從左到右顯示出來。
  • Tree Overview:全局概覽,以縮略的形式顯示。
  • Layout View:整體佈局圖,以手機屏幕上真實的位置呈現出來。單擊某一個控制項,會在Tree Overview視窗中顯示出對應的控制項。

根據上面講到的Hierarchy Viewer的4個四個子視窗,我們可以很容易的查看我們佈局控制項的層級關係。當然Hierarchy Viewer還可以查看某一個View的耗時,我們可以選擇某一個View,然後單擊下圖紅色箭頭標識的按鈕,這裡我們把他簡稱為Layout Time按鈕。


從圖中可以看出被選中的RelativeLayout自身的Measure、Layout和Draw的耗時數據都為n/a。單擊Layout Time按鈕後,就可以查看View的耗時情況了,如下圖所示。

QQ截圖20170324170337.pngQQ截圖20170324170337.png

從圖中可以看出,被選中的LinearLayout給出了自身Measure、Layout和Draw的耗時,並且它所包含的View中都有了三個指示燈,分別代表當前View在Measure、Layout和Draw的耗時,綠色代表比其他50%View的同階段(比如Measure階段)速度要快,黃色則代表比其他50%View同階段速度要慢,紅色則代表比其他View同階段都要慢,則需要註意了。如果想要看View的具體耗時,則點擊該View就可以了。

1.2 Android Lint

Android lint是在ADT 16提供的新工具,它是一個代碼掃描工具,通過代碼靜態檢查來發現代碼出現的潛在問題,並給出優化建議。檢查的範圍主要有以下幾點:

  • Correctness 正確性
  • Security 安全性
  • Performance 性能
  • Usability 可用性
  • Accessibility 可達性
  • Internationalization 國際化

Android Lint功能十分強大,這裡我們只關註XML佈局檢查,我們可以通過Android Studio的Analyze->Inspect Code來配置檢查的範圍,如下圖所示。

點擊上圖的OK按鈕後,就會進行代碼檢查,檢查的結果如下圖所示。

圖中列出了項目中出現的問題種類,以及每個問題種類的個數,問題種類包括我們前面提到的Correctness 、Internationalization 、Performance等。我們點擊展開最後的XML一項,點擊一個問題,就會出現如下圖的提示。

可以看出給出了Namespace declaration is never used的提示,並指出了問題所在的文件和行數,我們點擊數字3,直接跳入到問題的代碼,發現如下代碼:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    ...
View Code

第三行的Namespace 確實沒有被用到。如果想要自定義Android Lint的檢查提示,可以通過File->Settings->Editor->Inspections中來配置Android Lint,如下圖所示。

從圖中可以發現,我們可以配置Android Lint檢查的範圍以及問題的嚴重等級。

2.佈局優化方法

佈局的優化方法很多,主要包括合理運用佈局、Include、Merge、ViewStub,下麵我們來一一對這些內容進行講解。

2.1 合理運用佈局

我們常用的佈局主要有LinearLayout、RelativeLayout和FrameLayout等,合理的使用它們可以使得Android繪製工作量變少,性能得到提高。我們來舉個簡單的例子。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="佈局優化" />
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Merge" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="ViewStub" />
    </LinearLayout>
</LinearLayout>
View Code

上面的代碼用了兩個LinearLayout來進行佈局,運行效果如下圖所示。


我們用Hierarchy Viewer來查看層級情況,如下圖所示。

可以看到我們的佈局共有3層,一共含有5個View。如果我們用RelativeLayout來進行改寫呢?代碼如下所示。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/tv_text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="佈局優化" />
    <TextView
        android:id="@+id/tv_text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@id/tv_text1"
        android:text="Merge" />
    <TextView
        android:id="@+id/tv_text3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv_text2"
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@+id/tv_text1"
        android:text="ViewStub" />
</RelativeLayout>
View Code

我們只用了一個RelativeLayout來進行佈局。用Hierarchy Viewer來查看層級情況,如下圖所示。

佈局共有兩層,一共含有4個View。從這裡我們就可以看出我們用RelativeLayout減少了一層的佈局,當然這隻是一個簡單例子,如果佈局複雜,那麼合理的用RelativeLayout來替代LinearLayout會減少很多層佈局。
如果根據上面的例子來看,RelativeLayout的性能是比LinearLayout低,因為RelativeLayout中的View的排列方式是基於彼此依賴的。但是在實際開發中面對的情況比較多,不能輕易的說誰的性能更好。一般情況下,但是如果佈局層數較多時,推薦用RelativeLayout來實現。如果佈局嵌套較多,推薦使用LinearLayout來實現。

2.2 使用Include標簽來進行佈局復用

2.3 用Merge標簽去除多餘層級

Merge意味著合併,在合適的場景使用Merge標簽可以減少多餘的層級。Merge標簽一般和Include標簽搭配使用

merge標簽最好是來替代FrameLayout,或者是佈局方向一致的LinearLayout,比如當前父佈局LinearLayout的佈局方向是垂直的,包含的子佈局LinearLayout的佈局方向也是垂直的則可以用merge標簽.

2.4 使用ViewStub來提高載入速度

一個很常見的開發場景就是我們想要一個佈局時,並不是所有的控制項都需要顯示出來,而是顯示出一部分,對於這種情況,我們一般採用的方法就是使用View的GONE和INVISIBLE,但是這種方法效率不高,雖然是達到了隱藏的目的,但是仍在佈局當中,系統仍然會解析它們,我們可以用ViewStub來解決這一問題。
ViewStub是輕量級的View,不可見並且不占佈局位置。當ViewStub調用inflate方法或者設置可見時,系統會載入ViewStub指定的佈局,然後將這個佈局添加到ViewStub中,在對ViewStub調用inflate方法或者設置可見之前,它是不占佈局空間和系統資源的,它主要的目的就是為目標視圖占用一個位置。因此,使用ViewStub可以提高界面初始化的性能,從而提高界面的載入速度。

我們首先在佈局中加入ViewStub標簽,佈局代碼如下所示。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
  <ViewStub
      android:id="@+id/viewsub"
      android:layout_width="match_parent"
      android:layout_height="40dp"
      android:layout="@layout/titlebar"/>
   ...
</LinearLayout>

ViewStub標簽中用android:layout引用了此前寫好的佈局titlebar.xml。這時我們運行程式,ViewStub標簽所引用的佈局是顯示不出來的,因為引該局還沒有載入到ViewStub中,接下來在代碼中使用ViewStub:

public class MainActivity extends AppCompatActivity {
    private ViewStub viewsub;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewsub= (ViewStub) findViewById(R.id.viewsub);
//        viewsub.inflate();//1
        viewsub.setVisibility(View.VISIBLE);//2
    }
}

可以使用註釋1和註釋2處的代碼來將ViewStub引用的佈局載入到ViewStub中,這樣引用的佈局就顯示了出來。
View Code

在使用ViewStub時需要主要以下問題:

  • ViewStub只能載入一次,載入後ViewStub對象會被置為空,這樣當ViewStub引用的佈局被載入後,就不能用ViewStub來控制引用的佈局了。因此,如果一個控制項需要不斷的顯示和隱藏,還是要使用View的Visibility屬性。
  • ViewStub不能嵌套Merge標簽。
  • ViewStub操作的是佈局文件,如果只是想操作具體的View,還是要使用View的Visibility屬性。

3.避免GPU過度繪製

什麼是過度繪製呢?我們來打個比方,假設你要粉刷房子的牆壁,一開始刷了綠色,接著又刷了黃色,這樣黃色就將綠色蓋住,也就說明第一次的大量粉刷工作白做了。同樣手機屏幕繪製也是如此,過度繪製是指在屏幕上某個像素在同一幀的時間內被繪製多次,從而浪費了GPU和CPU的資源。產生這一原因主要有兩個原因:

  • 在XML佈局中,控制項有重疊且都有設置背景。
  • View的OnDraw中同一區域繪製多次。

過度繪製是不可避免的,但是過多的過度繪製會浪費很多資源,並且導致性能問題,因此,避免過度繪製是十分必要的。我們可以用Android系統中自帶的工具來檢測過度繪製。首先要保證系統版本在Android 4.1以上,接著在開發者選項中打開調試GPU過度繪製選項就可以進入GPU過度繪製模式,如下圖所示。

這時屏幕會出現出各種顏色,主要有以下幾種,如下圖所示。

各個顏色的定義為:

  • 原色: 沒有過度繪製 – 每個像素在屏幕上繪製了一次。
  • 藍色: 一次過度繪製 – 每個像素點在屏幕上繪製了兩次。
  • 綠色: 兩次過度繪製 – 每個像素點在屏幕上繪製了三次。
  • 粉色: 三次過度繪製 – 每個像素點在屏幕上繪製了四次。
  • 紅色: 四次或四次以上過度繪製 – 每個像素點在屏幕上繪製了五次或者五次以上。

最理想的是藍色,一個像素只繪製一次,合格的頁面繪製是白色、藍色為主,綠色以上區域不能超過整個的三分之一,顏色越淺越好。

避免過度繪製主要有以下幾個方案:
1.移除不需要的background。
2.在自定義View的OnDraw方法中,用canvas.clipRect來指定繪製的區域,防止重疊的組件發生過度繪製。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 大數據人工智慧淘寶天貓雙十一幕後:實時可視化查詢大屏 這張圖片來源於天貓雙十一數據直播,來自大數據可視化的魅力 【what】什麼是數據可視化? 塔夫特所說,“圖形表現數據。實際上比傳統的統計分析法更加精確和有啟發性。”對於廣大的編輯、設計師、運營分析師、大數據研究者等等都需要從不同維度、不同層面、不 ...
  • 1、表鎖和行鎖 表鎖和行鎖鎖的粒度不一樣,表鎖鎖住的是一整張表,行鎖鎖住的是表中的一行數據。 InnoDB使用的是行級鎖,MyISAM使用的是表級鎖。 註意:在InnoDB中,例如模糊查詢select * from tb where name like 'lin%'的時候也會鎖住一整張表。 2、共用 ...
  • 有表tb, 如下:id value 1 aa,bb2 aaa,bbb,ccc欲按id,分拆value列, 分拆後結果如下:id value 1 aa1 bb2 aaa2 bbb2 ccc --方法1.使用xml完成SELECT A.id, B.value FROM( SELECT id, [valu ...
  • 筆者在寫上一篇文章Java併發簡介 中腦子裡面同時也閃爍著,程式中有併發問題,那資料庫中也有類似問題嗎? 讓我們一起看一下吧! 事務是將一組讀寫操作組合在一起形成一個邏輯單元。這些操作要麼全部執行成功提交(commit),要麼全部中止失敗(abort,rollback),不會留下一個中間狀態的爛攤子 ...
  • 課時7 開發工具選用Webstorm課時8 Javascript基礎課時9 ES6基礎課時10 Node基礎課時11 React JSX基礎課時12 初識React組件化開發課時13 組件的生命周期課時14 組件間通信課時15 官方組件和文檔一覽課時16 項目的基本結構課時17 如何規範項目代碼課時 ...
  • Apple 終於在 Swift 4 的 Foundation 的模塊中添加了對 JSON 解析的原生支持。 雖然已經有很多第三方類庫實現了 JSON 解析,但是能夠看到這樣一個功能強大、易於使用的官方實現還是不免有些興奮。 值得註意的是,官方的實現方式適用於任何 Encoder/Decoder ,例 ...
  • 面對一些不規範的json,我們的gson解析經常會拋出各種異常導致app崩潰,這裡可以採取一些措施來避免 json異常的處理 我們期望在後臺返回的json異常時,也能解析成功,空值對應的轉換為預設值,如:newsId=0;這裡排除掉後臺開發人員輸出時給你做矯正,還是得靠自己啊 我們寫一個針對int值 ...
  • 前言:oc中枚舉的正確使用,可以增強代碼的可讀性,減少各種“錯誤”,讓代碼更加的規範。下麵先介紹枚舉的用法,最後介紹個人對枚舉的理解,什麼是枚舉,為什麼用枚舉。 一. OC中,枚舉的使用 1. 寫法1格式:關鍵字 enum 枚舉名字{枚舉成員,枚舉成員2}; 使用方法:enum 枚舉名稱 變數名稱 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...