1. 程式人生 > >效能優化之渲染效能優化

效能優化之渲染效能優化

1 知識儲備

  CPU::中央處理器,它集成了運算,緩衝,控制等單元,包括繪圖功能。CPU將物件處理為多維圖形、紋理(Bitmaps、Drawables等都是一起打包到統一的紋理)。
  GPU:一個類似於CPU的專門用來處理Graphics的處理器,作用用來幫助加快格柵化操作,當然,也有相應的快取資料(例如快取已經光柵化過的bitmap等)機制。
  OpenGL ES:是手持嵌入式裝置的3DAPI,跨平臺的、功能完善的2D和3D圖形應用程式介面API,有一套固定渲染管線流程.。
  DisplayList在Android把XML佈局檔案轉換成GPU能夠識別並繪製的物件。這個操作是在DisplayList的幫助下完成的,DisplayList持有所有將要交給GPU繪製到螢幕上的資料資訊。
  格柵化:是將Button,Shape,Path,String,Bitmap等元件等向量資源,轉化為一格格畫素點的畫素圖,顯示到螢幕上(硬體是:影象處理器,GPU顯示卡的處理器),過程圖如下:
這裡寫圖片描述


  垂直同步VSYNC:讓顯示卡的運算和顯示器重新整理率一致以穩定輸出的畫面質量。它告知GPU在載入新幀之前,要等待螢幕繪製完成前一幀。下面的三張圖分別是GPU和硬體同步所發生的情況。①Refresh Rate:螢幕一秒內重新整理螢幕的次數,由硬體決定,例如60Hz。②Frame Rate:GPU一秒繪製操作的幀數,比如:60fps。正常情況過程圖如下:
這裡寫圖片描述

2 渲染機制分析

2.1 渲染管線

  Android系統的渲染管線分為兩個關鍵元件:CPU和GPU,它們共同工作,在螢幕上繪製圖片,每個元件都有自身定義的特定流程。我們必須遵守這些特定的操作規則才能達到效果。
這裡寫圖片描述
  在CPU方面

,最常見的效能問題是:不必要和失效的佈局,這些內容必須在檢視層次結構中進行測量、清除並重新建立。引發這種問題通常有兩個原因:一是重建顯示列表的次數太多,二是花費太多時間作廢檢視層次並進行不必要的重繪,這兩個原因在更新顯示列表或者其他快取GPU資源時導致CPU工作過度。
  在GPU方面,最常見的問題是我們所說的:過度繪製(overdraw),通常是在畫素著色過程中,通過其他工具進行後期著色時浪費了GPU處理時間。
這裡寫圖片描述
  CPU在螢幕上繪製圖像前會向GPU輸入指定的基礎指令集,GPU使用這些指令集,主要是多邊形和紋理(圖片),這一過程通常使用的API就是Android的OpenGL ES。這就是說,在螢幕上繪製UI物件時無論是按鈕、路徑或者複選框,首先需要在CPU中計算並轉換為Polygons和Texture(多邊形和紋理),然後使用OpenGL ES將計算好的Polygons和Texture傳遞到GPU,最後GPU再進行格柵化。

2.2 渲染流程線

  UI物件—–>CPU處理為多維圖形,紋理—–>通過OpeGL ES介面呼叫GPU—–> GPU對圖進行光柵化(Frame Rate )—–>硬體時鐘(Refresh Rate)—–>垂直同步—–>投射到螢幕。
這裡寫圖片描述
圖片來源於:深入Android渲染機制

2.3 渲染時間線

  Android系統每隔16ms發出VSYNC訊號(1000ms/60=16.66ms),觸發對UI進行渲染, 如果每次渲染都成功,這樣就能夠達到流暢的畫面所需要的60fps,為了能夠實現60fps,這意味著計算渲染的大多數操作都必須在16ms內完成。
  正常情況:
這裡寫圖片描述
  渲染超時,計算渲染時間超過16ms。當這一幀畫面渲染時間超過16ms的時候,垂直同步機制會讓顯示器硬體等待GPU完成柵格化渲染操作,這樣會讓這一幀畫面,多停留了16ms、甚至更多。這樣就這造成了使用者看起來畫面停頓。
  當GPU渲染速度過慢,就會導致如下情況,某些幀顯示的畫面內容就會與上一幀的畫面相同:
  這裡寫圖片描述

3 渲染耗時的三個過程與優化方向

3.1 計算CPU渲染的耗時

  優化方向:CPU的優化,從減輕加工View物件成Polygons(多邊形)和Texture(紋理)來下手,測量、清除並重新建立不必要和失效的佈局
  任何時候View中的繪製內容發生變化時,都會重新執行建立DisplayList,渲染DisplayList,更新到螢幕上等一 系列操作。這個流程的表現效能取決於你的View的複雜程度,View的狀態變化以及渲染管道的執行效能。舉個例子:當View的大小發生改變,DisplayList就會重新建立,然後再渲染;而當View發生位移,則DisplayList不會重新建立,而是執行重新渲染的操作。當你的View過於複雜,操作又過於複雜,就會計算渲染時間超過16ms,產生卡頓問題。
  渲染耗時呈現工具—GPU呈現模式分析。每一條柱狀線都包含三部分:藍色代表測量繪製Display List的時間紅色代表OpenGL渲染Display List所需要的時間黃色代表CPU等待GPU處理的時間。中間有一根綠色的橫線,代表16ms,需要確保每一幀花費的總時間都低於這條橫線,這樣才能夠避免出現卡頓的問題。
這裡寫圖片描述

3.2 CPU將計算好的Polygons和Texture傳遞到GPU的時候也需要時間

  優化方向:OpenGL ES API允許資料上傳到GPU後可以對資料進行儲存,做了快取。

3.3 避免GPU進行格柵化時,過度繪製

  優化方向:儘量避免過度繪製(overdraw)
  GPU的繪製過程,就跟刷牆一樣,一層層的進行,16ms刷一次。這樣就會造成圖層覆蓋的現象,即無用的圖層還被繪製在底層,造成不必要的浪費。
這裡寫圖片描述
  過度繪製檢視工具使用步驟:設定 -> 開發者選項 -> 除錯GPU過度繪製 -> 顯示GPU過度繪製。圖例展示過度渲染:
這裡寫圖片描述
  隨著過度繪製的增多,標記顏色也會逐漸加深,例如1倍過度繪製會被標記為藍色,2倍、3倍、4倍過度繪製遵循同樣的模式。

4 渲染優化方法1——測量、清除並重新建立不必要和失效的佈局

4.1 Hierarchy Viewer層次佈局工具使用

4.1.1 減少不必要的層次,巧用Hierarchy Viewer工具

(1)Hierarchy Viewer在哪?
這裡寫圖片描述
(2)如何使用?一圖勝千言(建議在模擬器中使用)
這裡寫圖片描述

4.1.2 無法顯示3個圈圈怎麼辦?

(1)報錯,提示如下log:

[2016-11-20 15:59:49 - ViewServerDevice]Unable to debug device: nem_ul10-52F4C16425002867

(2)解決方法:將開發者模式關閉,再重新開啟。
這裡寫圖片描述

4.1.3 無法連線真機除錯怎麼辦?

  Android的官方文件中,有這麼一句話:出於安全考慮,Hierarchy Viewer只能連線Android開發版手機或是模擬器。推薦方法:谷歌大神romainguy在github的專案ViewServer,可以實現用HierarchyViewer工具對檢視和除錯應用的UI。。
  可以下載下來匯入到IDE中,裡面有個ViewServer的類,類註釋上也標註了用法,引入方法有兩種:

// 1 新增依賴
dependencies {
    compile project(':viewserver')
}

// 2 將ViewServer.java新增到專案中

  在BaseActivity中或者希望除錯的Activity以下該三個方法中,新增幾行程式碼:

public class BaseActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ViewServer.get(this).addWindow(this);
    }
    public void onResume() {
        super.onResume();
        ViewServer.get(this).setFocusedWindow(this);
    }
    public void onDestroy() {
        super.onDestroy();
        ViewServer.get(this).removeWindow(this);
    }
}

4.1.4 關注下面的三個圓圈

  從左到右依次,代表View的:Measure, Layout和Draw的效能,不同顏色代表不同的效能等級:
(1)綠色:渲染的管道階段,這個檢視的渲染速度快於至少一半的其他的檢視。
(2)黃色:渲染速度比較慢的50%。
(3)紅色:渲染速度非常慢。

4.1.5 測量結果分析

  紅色節點是代表應用效能慢的一個潛在問題,下面是幾個例子,如何來分析和解釋紅點的出現原因
(1)如果檢視層級結構中的根檢視,Messure階段為紅色,Layout階段為紅色,Draw階段為黃色,這個是比較常見的,因為這個節點是所有其它檢視的父類;
(2)如果一個檢視組裡面有許多的子節點,並且測量階段呈現為紅色,則需要觀察下子節點的繪製情況
(3)如果在葉節點或者ViewGroup中,只有極少的子節點,這可能在裝置上執行並不慢,但是需要指出為什麼這個節點是紅色的,可以藉助Systrace或者Traceview工具,獲取更多額外的資訊
(4)如果檢視結構中的一個葉子節點,有20個檢視是紅色的Draw階段,這是有問題的,需要檢查程式碼裡面的onDraw方法

4.2 優化佈局建議

4.2.1 佈局層級扁平化

  檢視耗時情況和佈局樹的深度的工具,提升佈局效能的關鍵點是:儘量保持佈局層級的扁平化,避免出現重複的巢狀佈局。使用線性佈局LinearLayout導致佈局層次變深,如果有這類問題,使用相對佈局RelativeLayout代替LinearLayout,減少佈局的層次;因為RelativeLayout的版本更優於LinearLayout的寫法。
  例如下面的例子,有2行顯示相同內容的檢視,分別用兩種不同的寫法來實現,他們有著不同的層級。
這裡寫圖片描述

4.2.2 每一個layout的外層父容器是否需要?

  沒有用的根佈局是指沒有背景繪製或者沒有大小限制的根佈局,這樣的佈局不會對UI效果產生任何影響。我們可以把沒有用的根佈局,通過merge標籤合併來減少層次;把沒有用的父佈局,刪除。以下是例子:當它的佈局程式碼如下:

<?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">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="startActivityB"
                android:text="啟動ActivityB" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="startActivityB"
                android:text="啟動ActivityB" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

這裡寫圖片描述
  把沒有用的根佈局,通過merge標籤合併來減少層次;把沒有用的父佈局,刪除後:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="startActivityB"
        android:text="啟動ActivityB" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="startActivityB"
        android:text="啟動ActivityB" />
</merge>

這裡寫圖片描述
  merge標籤即是合併。merge必須放在佈局檔案的根節點上;merge並不是ViewGroup,也不是View,對merge標籤設定的所有屬性都是無效的。如果是merge標籤,那麼直接將其中的子元素新增到merge標籤parent中,這樣就保證了不會引入額外的層級。所以:
  
(1)merge只能作為XML佈局的根標籤使用;

//LayoutInflate類的原始碼說明:
} else if (TAG_MERGE.equals(name)) {
    // 如果merge不是根節點,報錯
    throw new InflateException("<merge /> must be the root element");
}

(2)因為merge不是View,所以對merge標籤設定的所有屬性都是無效的。

(3)因為merge標籤並不是View,所以在通過LayoutInflate.inflate方法渲染的時候, 第二個引數必須指定一個父容器,且第三個引數必須為true,也就是必須為merge下的檢視指定一個父親節點。如:

//layoutInflater.inflate(parser, root, true)
layoutInflater.inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)

(4)如果Activity的佈局檔案根節點是FrameLayout,可以替換為merge標籤,這樣,執行setContentView之後,會減少一層FrameLayout節點;
  ①根節點是FrameLayout的效果

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:text="頂部Button" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:text="底部Button" />
</FrameLayout>

這裡寫圖片描述
  ②根節點是merge的效果

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:text="頂部Button" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:text="底部Button" />
</merge>

這裡寫圖片描述

(5)自定義View如果繼承LinearLayout,建議讓自定義View的佈局檔案根節點設定成merge,這樣能少一層節點。
  ①根節點是FrameLayout的效果

<?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">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1.0"
        android:text="第一個TextView"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1.0"
        android:text="第一個TextView" />
</LinearLayout>
//自定義的View,豎直方向的LinearLayout
public class MergeLayout extends LinearLayout {
    public MergeLayout(Context context) {
        super(context);
        LayoutInflater.from(context).inflate(R.layout.merge_activity, this, true);
    }
}

這裡寫圖片描述
  ②根節點是merge的效果

<?xml version="1.0" encoding="utf-8"?>
<!-- 習慣性的標記一下,MergeLayout佈局 android:orientation="vertical" -->
<merge xmlns:android="http://schemas.android.com/apk/res/android" >xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1.0"
        android:text="第一個TextView"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1.0"
        android:text="第一個TextView" />
</LinearLayout>
//自定義的View,豎直方向的LinearLayout
public class MergeLayout extends LinearLayout {
    public MergeLayout(Context context) {
        super(context);
        // 設定為數值方向的佈局
        setOrientation(VERTICAL);
        LayoutInflater.from(context).inflate(R.layout.merge_activity, this, true);
    }
}

這裡寫圖片描述

4.2.3 include佈局重用

  在Android的應用程式開發中,標題欄是必不可少的一個元素,大部分頁面都要用到,而且佈局都是一樣的,這時候使用include標籤就顯得極其的方便。使用時通常需要注意以下幾點:

include標籤的layout_*屬性會替換掉被include檢視的根節點的對應屬性。
include標籤的id屬性會替換掉被include檢視的根節點id,如果獲取根節點id檢視會丟擲空指標
<?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"
    android:background="#000000">

    <include layout="@layout/titlebar_layout"></include>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="這是內容區域"
        android:gravity="center"
        android:textSize="25sp"
        android:textColor="#ffffff"/>
</LinearLayout>

4.2.4 ViewStub標籤懶載入不常用的佈局

  ViewStub標籤最大的優點是當你需要時才會載入,使用他並不會影響UI初始化時的效能。各種不常用的佈局像:進度條、顯示錯誤訊息等,可以使用ViewStub標籤,以減少記憶體使用量,加快渲染速度。

<ViewStub
        android:id="@+id/stub"
        android:inflatedId="@+id/subTree"
        android:layout="@layout/my_sub_tree"//my_sub_tree.xml是懶載入檢視
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />  
//setVisibility可以被呼叫多次,但不建議這麼做  
//如果引用的檢視已經被垃圾回收器回收,則丟擲異常這也就是為什麼setVisibility可以呼叫多次,但是並不推薦這樣做的原因
((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);

// or  

//只能被呼叫一次,第二次呼叫會丟擲異常"ViewStub must have a non-null ViewGroup viewParent"
//因為ViewStub成功執行inflate方法後會呼叫parent.removeViewInLayout(this);
//將自己從父節點移除 所以ViewStub的inflate只能呼叫一次
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate(); 
// 方式1,獲取ViewStub,  
ViewStub listStub = (ViewStub) findViewById(R.id.stub);  
listStub.setVisibility(View.VISIBLE);  
ListView commLv = findViewById(R.id.stub_comm_lv);  
if (listStub.getVisibility() == View.VISIBLE) {  
    // 已經載入, 否則還沒有載入  
}  
// 方式二  
View commLv2;//全域性變數

ViewStub listStub2 = (ViewStub) findViewById(R.id.stub) ;  
if (commLv2 == null) {  
    commLv2 = (ListView)listStub2.inflate();  
} else {  
    // ViewStub已經載入  
}  

4.2.5 ListView不使用包裹內容屬性

//避免ListView的3個圓圈報紅,儘可能不使用包裹內容屬性。
 <ListView
      android:id="@+id/listView"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:scrollbars="vertical" />

5 渲染優化方法2——OpenGL ES系統優化

// 等待

6 渲染優化方法3——避免過度繪製(overdraw)

6.1 清除不必要的背景和圖片

這裡寫圖片描述
  開始清除前的渲染圖:
這裡寫圖片描述
  清除的內容:不必要的Background:

// 我們主佈局的檔案已經是background為white了,那麼可以移除ListView的白色背景
// Item佈局中的LinearLayout的
android:background="@android:color/darker_gray"
// Item佈局中的RelativeLayout的
android:background="@android:color/white"
// Item佈局中id為id_msg的TextView的
android:background="@android:color/white"

  清除後的渲染圖:
這裡寫圖片描述

6.2 保留Activity的灰色背景,又沒過度繪製

  我們的這個Activity要求背景色是灰色,我們的確在layout中去設定了背景色灰色,那麼這裡注意下,我們的Activity的佈局最終會新增在DecorView中,這個View會中的背景是不是就沒有必要了,所以我們希望呼叫mDecor.setWindowBackground(drawable),那麼可以在Activity呼叫getWindow().setBackgroundDrawable(null),可以避免過度繪製一層

// 在Activity的onCreate方法後
setContentView(R.layout.activity_overdraw_01);
getWindow().setBackgroundDrawable(null);
// 在layout中去設定了背景色colorPrimary
<?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:background="@color/fragment_bg"
    android:orientation="vertical">
</LinearLayout>

這裡寫圖片描述

6.3 清除ImageView載入後不必要的背景色或圖片

(1)設定方法
  這個背景比較難發現,主要需要看Adapter的getView的程式碼,上述程式碼你會發現,首先為每個icon設定了背景圖片(主要是當沒有icon圖的時候去顯示),然後又設定了一個頭像。那麼就造成了overdraw,有頭像的完全沒必要去繪製背景,所有修改程式碼:

Droid droid = getItem(position);
if(droid.imageId ==-1) {
    holder.icon.setBackgroundColor(0x4400ff00);
    holder.icon.setImageResource(Color.TRANSPARENT);
} else {
    holder.icon.setImageResource(droid.imageId);
    holder.icon.setBackgroundResource(Color.TRANSPARENT);
}

(2)看最後的Show GPU Overdraw 與最初的比較
這裡寫圖片描述

6.4 優化自定義View的計算

6.4.1 過度繪製的情況

(1)經常會由於疏忽造成很多不必要的繪製,比如大家看下面這樣的圖。多張卡片疊加,那麼如果你是一張一張卡片從左到右的繪製,效果肯定沒問題,但是疊加的區域肯定是過度繪製了。並且material design對於介面設計的新的風格更容易造成上述的問題。那麼有什麼好的方法去改善呢?
這裡寫圖片描述
(2)答案是有的:Android的Canvas物件給我們提供了很便利的方法clipRect裁剪掉View的覆蓋部分,增加cpu的計算量來優化GPU的渲染。

6.4.2 原始碼演示

(1)Activity程式碼

public class OverDrawActivity02 extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new CardView(this));
    }
}

(2.1)未修改前CardView 程式碼

/**
 * CardView 
 */
public class CardView extends View {
    private Bitmap[] mCards = new Bitmap[3];
    private int[] mImgId = new int[]{R.drawable.alex, R.drawable.chris, R.drawable.claire};
    public CardView(Context context) {
        super(context);
        Bitmap bm = null;
        for (int i = 0; i < mCards.length; i++) {
            bm = BitmapFactory.decodeResource(getResources(), mImgId[i]);
            mCards[i] = Bitmap.createScaledBitmap(bm, 400, 600, false);
        }
        setBackgroundColor(0xff00ff00);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        canvas.translate(20, 120);
        for (Bitmap bitmap : mCards) {
            canvas.translate(120, 0);
            canvas.drawBitmap(bitmap, 0, 0, null);
        }
        canvas.restore();
    }
}

(2.2)修改後的CardView 程式碼

/**
 * 分析得出,除了最後一張需要完整的繪製,其他的都只需要繪製部分;所以我們在迴圈的時候,給i到n-1都添加了clipRect的程式碼。
 */
 @Override
 protected void onDraw(Canvas canvas) {
     super.onDraw(canvas);
     canvas.save();
     canvas.translate(20, 120);
     for (int i = 0; i < mCards.length; i++) {
         canvas.translate(120, 0);
         canvas.save();
         if (i < mCards.length - 1) {
             canvas.clipRect(0, 0, 120, mCards[i].getHeight());
         }
         canvas.drawBitmap(mCards[i], 0, 0, null);
         canvas.restore();
     }
     canvas.restore();
}

6.4.3 最後的效果圖

這裡寫圖片描述

7 總結

  效能優化其實不僅僅是一種技術,而是一種思想,你只聽過它的高大上,卻不知道它其實就是各個細節處的深入研究和處理。當然,有的時候也需要自己進行權衡效果和效能,根據需求進行選擇。還有,Android Device Monitor是個好東西,簡直就是效能優化大本營,效能優化的工具基本都在其中。
  所以在平時的開發過程中,養成良好的思考習慣是第一步:

//寫程式碼的時候要想:1)我的程式碼是不是多餘? 
(2)我的物件有沒有必要在迴圈中建立? 
(3)我的計算方法是不是最優?
//畫介面的時候要想: 1)佈局是否有背景? 
(2)是否可以刪掉多餘的佈局? 
(3)佈局是否扁平化,移除非必需的UI組?
(4)自定義View是否進行了裁剪處理? 

8 參考連結

相關推薦

效能優化渲染效能優化

1 知識儲備   CPU::中央處理器,它集成了運算,緩衝,控制等單元,包括繪圖功能。CPU將物件處理為多維圖形、紋理(Bitmaps、Drawables等都是一起打包到統一的紋理)。   GPU:一個類似於CPU的專門用來處理Graphics的處理器,作用

KVM總結-KVM效能優化磁碟IO優化

前面講了KVM CPU(http://blog.csdn.net/dylloveyou/article/details/71169463)、記憶體(http://blog.csdn.net/dylloveyou/article/details/71338378)的優化,下面接著第三塊的內容,KVM磁

MySQL(二) —— MySQL效能優化 SQL語句優化

          SQL語句優化   MySQL優化的目的   1、避免出現頁面訪問錯誤:或由於資料庫連線超時 timeout 產生頁面5xx錯誤;或由於慢查詢造成頁面無法載入;或由於阻        塞造成資料無法提交;

【MySQL資料庫】效能優化索引及優化(一)

一、Mysql效能優化之影響效能的因素 1.商業需求的影響 不合理的需求造成的資源投入產出,這裡就用一個看上去很簡單的功能分析。需求:一個論壇帖子的總量統計,附加要求:實時更新。從功能上看來是非常容易實現的,執行一條select count(*)from表名就可以得到結果,但是如果我們採

Mysql資料庫效能優化查詢效能優化

一、前言:為啥查詢速度會變慢? 通常來說,查詢的生命週期大致分為從客戶端、到伺服器,然後在伺服器上進行解析,生成執行計劃,執行,並返回結果給客戶端。其中執行可以說是最重要的階段,這其中包括了大量為了檢索資料到儲存引擎的呼叫以及呼叫後的資料處理,包括排序和分組等。在每一個消耗大量時間的查

Mysql效能優化資料型別優化

一、選擇正確的資料型別對於獲得高效能至關重要 1.1更小的通常更好 佔用更少的磁碟、記憶體和CPU快取 1.2儘量避免null 如果查詢中包含可為null的列,對Mysql來說更難優化,因為可為null的列使得索引、索引統計和值都更復雜。會使用更多的儲存空間. 2、整數和實數

MySQL 資料庫效能優化表結構優化

很多人都將 資料庫設計正規化 作為資料庫表結構設計“聖經”,認為只要按照這個正規化需求設計,就能讓設計出來的表結構足夠優化,既能保證效能優異同時還能滿足擴充套件性要求。殊不知,在N年前被奉為“聖經”的資料庫設計3正規化早就已經不完全適用了。這裡我整理了一些比較常見的資料庫表結構設計方面的優化技巧,希

Android效能優化圖片壓縮優化

1 分類Android圖片壓縮結合多種壓縮方式,常用的有尺寸壓縮、質量壓縮、取樣率壓縮以及通過JNI呼叫libjpeg庫來進行壓縮。 參考此方法:Android-BitherCompress 備註:對於資源圖片直接使用:tiny壓縮 2 質量壓縮(1)原理:保持畫素的前提下改變圖片的位深及透明度,(即:通

Java效能優化作業系統層面優化

目前常用的作業系統分為:windows,Unix(Linux),我們會分別介紹在不同系統上的調優。 一,概念 效能監控:一種以非侵入方式收集或檢視應用執行效能資料的活動,通常是指在生產,質量評估, 開發環境中實施的帶有預防或主動性的活動。 效能分析:一種以侵入方式收集執行效能資料的活

Linux運維Nginx軟體優化Nginx效能優化

1. 優化nginx worker進行個數 nginx服務主要有兩個重要程序: 01) master程序:可以控制nginx服務的啟動 停止 或重啟 02) worker程序:處理使用者請求資訊,幫助使用者向後端服務進行請求(php mysql) 新增worker程序方法

MySQL(二) —— MySQL效能優化 SQL語句優化

          SQL語句優化 MySQL優化的目的   1、避免出現頁面訪問錯誤:或由於資料庫連線超時 timeout 產生頁面5xx錯誤;或由於慢查詢造成頁面無法載入;或由於阻        塞造成資料無法提交;   2、增加資料庫的穩定性:避免由於低效查詢

KVM總結-KVM效能優化網路效能優化

首先,我給大家看一張圖,這張圖是資料包從虛擬機器開始然後最後到物理網絡卡的過程。 我們分析下這張圖,虛擬機器有資料包肯定是先走虛擬機器自身的那張虛擬網絡卡,然後發到中間的虛擬化層,再然後是傳到宿主機裡的核心網橋中,最後傳到物理網絡卡,這個過程很好理解。 那麼我們要做網

資料庫效能優化SQL語句優化

避免使用HAVING子句, HAVING 只會在檢索出所有記錄之後才對結果集進行過濾. 這個處理需要排序,總計等操作. 如果能通過WHERE子句限制記錄的數目,那就能減少這方面的開銷. (非oracle中)on、where、having這三個都可以加條件的子句中,on是最先執行,where次之,having最

Mysql效能優化快取引數優化

資料庫屬於 IO 密集型的應用程式,其主要職責就是資料的管理及儲存工作。而我們知道,從記憶體中讀取一個數據庫的時間是微秒級別,而從一塊普通硬碟上讀取一個IO是在毫秒級別,二者相差3個數量級。所以,要優化資料庫,首先第一步需要優化的就是 IO,儘可能將磁碟IO轉化為記憶體IO。本文先從 MySQL 資料庫IO相

Web效能優化CSS效能優化

非常感謝原文作者的分享,個人覺得非常有用.所以將原文進行翻譯,如果有錯誤,麻煩回覆指出 附上原文地址 什麼是高效的CSS?不同的選擇器對效能的影響如何?是花括號裡的屬性重要還是選擇器重要?. 我們在做優化網站的效能時,CSS的優化往往是

MySQL 資料庫效能優化快取引數優化

https://blog.csdn.net/truelove12358/article/details/51956356   部落格 學院 下載 圖文課 論壇 APP 問答 商城 VIP會員 活動 招聘 ITe

Oracle效能優化高階SQL優化(一)

  使用基於規則的優化器(CBO)時,Oracle解析器按照從右到左的順序處理FROM子句的表明,即FROM子句中最後的表(驅動表)會最先被處理。   當FROM子句包含多個表時,建議將記錄最少的表(一般是字典表)放在最後面。當Oracle處理多個表時,一般採用排序或合併的方式連線這些表,系統首先會掃描FR

資料庫效能優化SQL語句優化1

一、問題的提出 在應用系統開發初期,由於開發資料庫資料比較少,對於查詢SQL語句,複雜檢視的的編寫等體會不出SQL語句各種寫法的效能優劣,但是如果將應用系統提交實際應用後,隨著資料庫中資料的增加,系統的響應速度就成為目前系統需要解決的最主要的問題之一。系統優化中一個很重要的方面就是SQL語句的優化。對於

每天學點java效能優化字串處理優化

<pre code_snippet_id="1604271" snippet_file_name="blog_20160310_1_3195965" name="code" class="java"> 在java語言中,java的設計者對String物件進行

Android效能優化冷啟動優化

1.什麼是冷啟動[啟動時間比較長]:在應用啟動前,系統沒有該應用的任何程序資訊。2.什麼是熱啟動[啟動時間比較短] :使用者按了返回鍵,又馬上重新啟動了此應用。3.冷啟動會走application這個類,熱啟動就不會走application這個類4.冷啟動流程5.冷啟動優化