Android 效能優化方法
Android 效能優化方法
開發中常會做一些效能優化,主要優化內容包括佈局層級優化,繪製優化,記憶體洩露優化(音訊,視訊,io等回收),響應速度優化,ListView優化,Bitmap優化,執行緒優化以及一些效能優化,在面試中面試官也會經常問到該點 . 前面博文我收集的各大廠等面試題
文章目錄
佈局優化
佈局優化思想,儘量減少佈局檔案的層級,層級少,意味Android繪製時的工作量少了,程式的效能自然提高了.
- 刪除佈局中無用的控制元件和層級
- 有選擇使用效能較低的ViewGroup,如:RelativeLayout
- 優先使用LinearLayout,相對RelativeLayout,其功能比較簡單,花費較少的CPU時間
- 需要複雜巢狀實現效果時,這種情況下建議採用RelativeLayout
- 採用標籤在於佈局重用,標籤降低減少佈局層級和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方法要避免執行大量的操作,如下三點
- onDraw中不要建立新的區域性物件,因為onDraw方法可能會被頻繁呼叫,這樣就會在一瞬間產生大量的臨時物件,這不僅佔用了過多的記憶體而且還會導致系統更加頻繁gc,降低了程式的執行效率
- onDraw方法中不要做耗時的任務,也不能執行復雜的迴圈操作,儘管每次迴圈都很輕量級,但是大量的迴圈任然十分搶佔CPU的時間片,這回造成View的繪製過程不流暢.
- Google官方給出的效能優化典範中的標準,View的繪製幀率保證60fps是最佳的,這就要求每幀的繪製時間不超過16ms(16 = 1000/60),雖然程式很難保證16ms這個時間,但是儘量降低onDraw方法的複雜度總是切實有效的.
記憶體洩露優化
記憶體洩露在開發過程中是一個需要重視的問題,但是由於記憶體洩露問題 對開發人員的經驗和開發意識有較高的要求,因此這也是開發人員最容易犯的錯誤之一.記憶體洩露的優化分為兩個方面,一方面是開發過程中避免寫出有記憶體洩露的程式碼.另一方面是通過一些分析工具找出潛在的記憶體洩露
- 靜態變數導致的記憶體洩露,(在dalvik虛擬機器中,static變數所指向的記憶體引用,如果不把它設定為null,GC是永遠不會回收這個物件的),處理: 物件=null;
- 單例模式導致的記憶體洩露,如下
單例模式導致的記憶體洩露: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;
}
}
- 屬性動畫導致的記憶體洩露,屬性動畫無限迴圈動畫,Activity與View相互持有,導致Activity無法釋放. 解決: onDestroy 對動畫 animator.cancel()來停止動畫
響應速度優化
響應速度優化的核心思想是避免在主執行緒中做耗時操作,這裡具體可參考前面的文章.耗時操作放線上程中去執行,即採用非同步的方式執行耗時操作.響應速度過慢更多地體現在Activity的啟動速度上面,如果在主線中做太多事情,會導致Activity啟動時出現黑屏現象,甚至出現ANR, Android規定,Activity如果5秒鐘之內無法響應螢幕觸控事件或者鍵盤輸入時間就會出現ANR,而BroadcastReceiver如果10秒鐘之內還未執行完操作也會出現ANR.
ListView和Bitmap優化
listview優化
-
convertView的使用,主要優化載入佈局問題
-
內部類ViewHolder的使用,採用ViewHolder並避免在getView中執行耗時操作
-
滑動的時候不載入圖片
在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
}
});
-
將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" />
-
降低item的佈局的深度
儘量降低item佈局深度,由於當滑動ListView的時候,這回直接導致測量與繪製,因此會浪費大量的時間。所以我們應該將一些不必要的佈局巢狀關係去掉。
-
分批載入與分頁載入相結合
執行緒優化
執行緒優化的核心思想是採用執行緒池,避免程式中存在大量的Thread.執行緒池可以重用內部的執行緒,從而避免了執行緒的建立和銷燬所帶來的效能開銷,同時執行緒池還能有效地控制執行緒池的最大併發數,避免大量的執行緒因互相搶佔系統資源從而導致阻塞現象的發生.因此在實際開發中,我們要儘量採用執行緒池,而不是每次都要建立一個Thread物件
心靈激勵
激勵:為自己技術增值,量變引起質變.博主依稀記得當前的語文老師說的一句話:“態度決定高度”,博主想對所有的讀者說"過去的已經過去,你的未來由你現在把握".
尾言
本文如有錯誤或不當之處,歡迎讀者留言斧正,互相交流學習,博主不勝感激.聯絡郵箱[email protected]