Android的性能優化方法

Android的性能優化方法

主要介紹一些佈局優化,繪製優化,內存泄露優化,響應速度優化,ListView優化,Bitmap優化,線程優化以及一些性能優化建議。

1.佈局優化

思想:儘量減少佈局文件層級,這樣Android繪製時的工作量就減少了。
首先刪除佈局中無用的控件和層級,其次有選擇地使用性能較低的ViewGroup,比如RelativeLayout。RelativeLayout的功能比較複雜,它的佈局過程需要花費更多的CPU時間。FrameLayout和LinearLayout一樣都是簡單高效的ViewGroup。但很多時候單純通過一個Linealayout或者FrameLayout無法實現效果,需要通過嵌套來實現,這是建議使用RelativeLayout,因爲嵌套相當於增加了佈局的層級,同樣降低程序的性能。
另一箇中手段是採用標籤,標籤和ViewStub。主要用於佈局重用,標籤一般和配合使用,可以降低佈局層級,而ViewStub 則提供按需加載的功能,當需要時纔會將ViewStub中的佈局加載到內存,這提高了程序的初始化效率。

<include>標籤

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.toolbar.MainActivity">

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

<TextView
    android:layout_width="match_parent"
    android:text="哈哈哈哈哈"
    android:layout_height="match_parent" />

</LinearLayout>

<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">

    <include layout="@layout/layout" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name" />
</merge>

如果外部LinearLayout是豎直,而merge中也採用豎直方向的LinearLayout,可以通過標籤代替。

ViewStub

繼承了View,非常輕量級且寬/高都是0,因此它本身不參與佈局繪製過程。

<ViewStub
        android:id="@+id/stub_import"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:inflatedId="@+id/panel_import" />

通過下邊兩種方式

((ViewStub)findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);

或者

View importPanel=(ViewStub)findViewById(R.id.stub_import).inflate();

調上述兩個方法後ViewStub就會被它內部的佈局替換掉,就再是整個佈局結構中的一部分了。另外,目前ViewStub還不支持標籤。

ViewStub只能Inflate一次,之後ViewStub對象會被置爲空。按句話說,某個被ViewStub指定的佈局被Inflate後,就不會夠再通過ViewStub來控制它了。
參考使用:http://blog.csdn.net/hitlion2008/article/details/6737537/

2.繪製優化

繪製優化就是指View的onDraw方法要避免執行大量的操作,主要體現在兩個方面:

首先,onDraw中不要創建新的局部對象,這是因爲onDraw方法可能會被頻繁的調用,這樣就會一瞬間產生大量的臨時對象,這不僅佔用了過多的內存而且還會導致系統更加頻繁gc,降低了程序的執行效率。

另一方面,onDraw方法中不能做耗時的任務,也不能執行成千上萬次的循環操作,儘管每次循環都很輕量級,但是大量的循環仍然十分槍戰CPU的時間片,這會造成View的繪製過程不流暢。按照Google官方給出的性能優化典範中的標準,View的繪製幀率保證60fps是最佳的,這就要求每真幀的繪製時間不超過16ms(16ms=1000/60),雖然程序很難保證16ms這個時間,但是儘量降低onDraw方法的複雜度總是有效的。

3.內存泄露優化

場景1:靜態變量導致的內存泄露
如下Acitivity無法正常銷燬,因靜態變量sContext引用了它。

public class MainActivity extends Activity{
private static final String TAG="MainAcitivity";

private static Context sContext;
@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    sContext=this;

場景2:單例模式導致的內存泄露
Activity實現單例模式的接口並向它註冊監聽,但是缺少註冊的操作會引起內存泄露,泄露的原因是Acitivity的對象被單例模式所持有,而單利模式的特點是其生命週期和Application保持一致,因此Acitivity對象無法被及時釋放。

場景3:屬性動畫導致的內存泄露
屬性動畫中有一類無限循環的動畫,如果Activity中播放此動畫但沒有在onDestroy中去停止動畫,那麼動畫會一致播放下去,並且Activity的View會被動畫持有,而View又持有了Activity,最終Activity無法釋放。

ObjectAnimator animator=ObjectAnimator.ofFloat(mButton,"rotation",0,360).setDuration(200));
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.start();

解決方法是在Activity的onDestory方法中調用animator.cancel();來停止動畫。

4.相應速度優化和ANR日誌分析

思想:避免主線程做耗時操作,有的耗時操作可以放到線程中去執行,即採用異步的方式執行耗時操作,主要體現在Activity的啓動速度上面,如果主線程做太多事情,會導致Activity啓動時出現黑屏現象,甚至ANR。
在實際開發中,ANR很難從代碼上發現,如果程序遇到ANR,系統會在/data/anr目錄下創建一個文件traces.txt,通過分析這個文件就能定位出ANR的原因。

5.ListView和Bitmap優化

ListView優化,首先採用ViewHolder 並避免在getView中執行耗時操作,其次要根據列表的滑動狀態來控制任務的執行頻率,最後可以嘗試開啓硬件加速來使ListView的滑動更加流暢。

Bitmap的優化主要通過BitmapFactory.Options來根據需要對圖片進行採樣,得到inSampleSize採樣率。

6.線程優化

思想:採用線程池,避免程序中存在大量的Thread。線程池可以重用內部的線程,從而避免線程的創建和銷燬帶來的性能開銷,同事線程池還能有效的控制線程池的最大併發數,避免大量的線程因互相搶佔系統資源而導致阻塞現象發生。因此在時間開發中,我們儘量採用線程池,而不是每次都要創建一個Thread對象。

7.建議

  • 避免創建過多的對象;
  • 不要過多使用枚舉,枚舉佔用的內存空間要比整形大;
  • 常量請使用static final來修飾;
  • 使用一些Android特有的數據接口,如SpareArray和Pair等,他們都具有更好的性能;
  • 適當使用軟引用和弱引用;
  • 採用內存緩存和磁盤緩存;
  • 儘量採用靜態內部類,這樣可以避免潛在的由於內部類而導致內存泄露。

內存泄露分析工具MAT,下載地址:http://www.eclipse.org/downloads/download.php

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章