1. 程式人生 > >Android 效能優化方法

Android 效能優化方法

Android 效能優化方法

開發中常會做一些效能優化,主要優化內容包括佈局層級優化,繪製優化,記憶體洩露優化(音訊,視訊,io等回收),響應速度優化,ListView優化,Bitmap優化,執行緒優化以及一些效能優化,在面試中面試官也會經常問到該點 . 前面博文我收集的各大廠等面試題

文章目錄

佈局優化

佈局優化思想,儘量減少佈局檔案的層級,層級少,意味Android繪製時的工作量少了,程式的效能自然提高了.

  1. 刪除佈局中無用的控制元件和層級
  2. 有選擇使用效能較低的ViewGroup,如:RelativeLayout
  3. 優先使用LinearLayout,相對RelativeLayout,其功能比較簡單,花費較少的CPU時間
  4. 需要複雜巢狀實現效果時,這種情況下建議採用RelativeLayout
  5. 採用標籤在於佈局重用,標籤降低減少佈局層級和ViewStub按需載入
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="@color/main_background_color"
              android:fitsSystemWindows="true"
              android:orientation="vertical">

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="10dp"
        android:layout_weight="1"
        android:orientation="vertical">

        <!--個人資訊-->
        <RelativeLayout
            android:id="@+id/rl_setting_user_message"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="@color/white">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="15dp"
                android:text="個人資訊"
                android:textColor="@color/text_color_black"
                android:textSize="16sp"/>

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_marginRight="15dp"
                android:src="@mipmap/arrow"/>

        </RelativeLayout>

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:src="@color/button_stroke"/>

        <!--賬號安全-->
        <RelativeLayout
            android:id="@+id/rl_setting_user_safe"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="@color/white">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="15dp"
                android:text="賬號安全"
                android:textColor="@color/text_color_black"
                android:textSize="16sp"/>

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_marginRight="15dp"
                android:src="@mipmap/arrow"/>

        </RelativeLayout>

        <!--訊息通知-->
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_marginTop="15dp"
            android:background="@color/white">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="15dp"
                android:text="訊息通知"
                android:textColor="@color/text_color_black"
                android:textSize="16sp"/>

            <Switch
                android:id="@+id/switch_message"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_marginRight="15dp"
                android:showText="false"
                android:textOff=""
                android:textOn=""
                android:thumb="@drawable/swtich_thumb_selector"
                android:track="@drawable/swtich_track_selector"
                />

        </RelativeLayout>

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:src="@color/button_stroke"/>

        <!--音效-->
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="@color/white">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="15dp"
                android:switchMinWidth="40dp"
                android:switchPadding="10dp"
                android:text="音效"
                android:textColor="@color/text_color_black"
                android:textOff="開"
                android:textOn="關"
                android:textSize="16sp"
                android:typeface="normal"/>

            <Switch
                android:id="@+id/switch1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_marginRight="15dp"
                android:gravity="center_vertical"
                android:showText="false"
                android:textOff=""
                android:textOn=""
                android:thumb="@drawable/swtich_thumb_selector"
                android:track="@drawable/swtich_track_selector"
                />

        </RelativeLayout>

        <!--版本號-->
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_marginTop="15dp"
            android:background="@color/white">

            <TextView
                android:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="15dp"
                android:text="版本"
                android:textColor="@color/text_color_black"
                android:textSize="16sp"/>

            <TextView
                android:id="@+id/version"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_marginRight="15dp"
                android:textColor="@color/color_bfbfbf"
                android:textSize="16sp"/>

        </RelativeLayout>

    </LinearLayout>

    <Button
        android:id="@+id/bt_login_out"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_marginBottom="15dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:background="#ff4a2c"
        android:gravity="center"
        android:text="登出賬號"
        android:textColor="@color/white"
        android:textSize="18sp"/>


</LinearLayout>

繪製優化

繪製優化是指View的onDraw方法要避免執行大量的操作,如下三點

  1. onDraw中不要建立新的區域性物件,因為onDraw方法可能會被頻繁呼叫,這樣就會在一瞬間產生大量的臨時物件,這不僅佔用了過多的記憶體而且還會導致系統更加頻繁gc,降低了程式的執行效率
  2. onDraw方法中不要做耗時的任務,也不能執行復雜的迴圈操作,儘管每次迴圈都很輕量級,但是大量的迴圈任然十分搶佔CPU的時間片,這回造成View的繪製過程不流暢.
  3. Google官方給出的效能優化典範中的標準,View的繪製幀率保證60fps是最佳的,這就要求每幀的繪製時間不超過16ms(16 = 1000/60),雖然程式很難保證16ms這個時間,但是儘量降低onDraw方法的複雜度總是切實有效的.

記憶體洩露優化

記憶體洩露在開發過程中是一個需要重視的問題,但是由於記憶體洩露問題 對開發人員的經驗和開發意識有較高的要求,因此這也是開發人員最容易犯的錯誤之一.記憶體洩露的優化分為兩個方面,一方面是開發過程中避免寫出有記憶體洩露的程式碼.另一方面是通過一些分析工具找出潛在的記憶體洩露

  1. 靜態變數導致的記憶體洩露,(在dalvik虛擬機器中,static變數所指向的記憶體引用,如果不把它設定為null,GC是永遠不會回收這個物件的),處理: 物件=null;
  2. 單例模式導致的記憶體洩露,如下

單例模式導致的記憶體洩露:Activty是間接繼承於Context的,當這Activity退出時,Activity應該被回收, 但是單例中又持有它的引用,導致Activity回收失敗,造成記憶體洩漏。

package com.kx.singleinstance;

import android.content.Context;

/**
 * @ 建立:   kx
 * @ 時間:    2018/11/13
 * @ 描述:
 */

public class AppManager  {

    private static AppManager instance;
    
    private  Context mContext;

    public AppManager(Context context) {
        mContext = context;
    }

    public  static AppManager getInstance(Context context){
        if(instance == null){
            instance = new AppManager(context);
        }
        return  instance;
    }
}

單例模式導致的記憶體洩露改進:使用Applicaton的Context,而我們單例的生命週期和應用的一樣長,這樣就防止了記憶體洩漏。

package com.kx.singleinstance;

import android.content.Context;

/**
 * @ 建立:   kx
 * @ 時間:    2018/11/13
 * @ 描述:
 */

public class AppManager  {


    private static AppManager instance;
    
    private  Context mContext;

    public AppManager(Context context) {
        //使用Applicaton的Context,而我們單例的生命週期和應用的一樣長,這樣就防止了記憶體洩漏。
        mContext = context.getApplicationContext();
    }

    public  static AppManager getInstance(Context context){
        if(instance == null){
            instance = new AppManager(context);
        }
        return  instance;
    }
}

  1. 屬性動畫導致的記憶體洩露,屬性動畫無限迴圈動畫,Activity與View相互持有,導致Activity無法釋放. 解決: onDestroy 對動畫 animator.cancel()來停止動畫

響應速度優化

響應速度優化的核心思想是避免在主執行緒中做耗時操作,這裡具體可參考前面的文章.耗時操作放線上程中去執行,即採用非同步的方式執行耗時操作.響應速度過慢更多地體現在Activity的啟動速度上面,如果在主線中做太多事情,會導致Activity啟動時出現黑屏現象,甚至出現ANR, Android規定,Activity如果5秒鐘之內無法響應螢幕觸控事件或者鍵盤輸入時間就會出現ANR,而BroadcastReceiver如果10秒鐘之內還未執行完操作也會出現ANR.

ListView和Bitmap優化

listview優化

  1. convertView的使用,主要優化載入佈局問題

  2. 內部類ViewHolder的使用,採用ViewHolder並避免在getView中執行耗時操作

  3. 滑動的時候不載入圖片

    在ListView滑動的時候載入圖片,那樣會使ListView變得卡頓,所以我們須要再監聽器裡面監聽ListView的狀態。假設滑動的時候,停止載入圖片,假設沒有滑動,則開始載入圖片

listView.setOnScrollListener(new OnScrollListener() {

            @Override
            public void onScrollStateChanged(AbsListView listView, int scrollState) {
                    //停止載入圖片 
                    if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
                            imageLoader.stopProcessingQueue();
                    } else {
                    //開始載入圖片
                            imageLoader.startProcessingQueue();
                    }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                    // TODO Auto-generated method stub

            }
    });
  1. 將ListView的scrollingCache和animateCache設定為false

    A.scrollingCache: scrollingCache本質上是drawing cache,你能夠讓一個View將他自己的drawing儲存在cache中(儲存為一個bitmap),這樣下次再顯示View的時候就不用重畫了,而是從cache中取出。預設情況下drawing cahce是禁用的。由於它太耗記憶體了,可是它確實比重畫來的更加平滑。而在ListView中,scrollingCache是預設開啟的,我們能夠手動將它關閉。

    B.animateCache: ListView預設開啟了animateCache,這會消耗大量的記憶體,因此會頻繁呼叫GC,我們能夠手動將它關閉掉

<ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:divider="@color/list_background_color"
        android:dividerHeight="0dp"
        android:listSelector="#00000000"
        android:scrollingCache="false"
        android:animationCache="false"
        android:smoothScrollbar="true"
        android:visibility="gone" />
  1. 降低item的佈局的深度

    儘量降低item佈局深度,由於當滑動ListView的時候,這回直接導致測量與繪製,因此會浪費大量的時間。所以我們應該將一些不必要的佈局巢狀關係去掉。

  2. 分批載入與分頁載入相結合

執行緒優化

執行緒優化的核心思想是採用執行緒池,避免程式中存在大量的Thread.執行緒池可以重用內部的執行緒,從而避免了執行緒的建立和銷燬所帶來的效能開銷,同時執行緒池還能有效地控制執行緒池的最大併發數,避免大量的執行緒因互相搶佔系統資源從而導致阻塞現象的發生.因此在實際開發中,我們要儘量採用執行緒池,而不是每次都要建立一個Thread物件

心靈激勵

激勵:為自己技術增值,量變引起質變.博主依稀記得當前的語文老師說的一句話:“態度決定高度”,博主想對所有的讀者說"過去的已經過去,你的未來由你現在把握".

尾言

本文如有錯誤或不當之處,歡迎讀者留言斧正,互相交流學習,博主不勝感激.聯絡郵箱[email protected]