天天看點

Android 性能優化最佳實踐什麼是性能優化1、布局優化2、繪制優化3、記憶體優化4、 啟動速度優化 5、包體優化6、 耗電優化 7、 ListView 和 Bitmap 優化 8、 響應速度優化 9、 線程優化 10、 微優化 結尾

什麼是性能優化

Android 性能優化最佳實踐什麼是性能優化1、布局優化2、繪制優化3、記憶體優化4、 啟動速度優化 5、包體優化6、 耗電優化 7、 ListView 和 Bitmap 優化 8、 響應速度優化 9、 線程優化 10、 微優化 結尾

性能優化簡介

快,穩,省,小,這四點很形象的代表了性能的四個方面,同時也讓我們知道我們 App 現在是否是款性能良好的 APP,如果有一項不達标,那麼說明我們的應用有待優化。

很多時候我們注重功能實作,保證能用,但是我們會發現,這樣的應用很難拿的出手,裡面的槽點太多了,性能很差,但是又不知道從哪裡下手進行優化,那麼我們就一步一步來,看看我們到底應該怎麼優化我們的 APP。

1、布局優化

螢幕上的某個像素在同一幀的時間内被繪制了多次。在多層次的 UI 結構裡 面,如果不可見的 UI 也在做繪制的操作,這就會導緻某些像素區域被繪制了多 次。這就浪費大量的 CPU 以及 GPU 資源。

1.0、防止過度繪制

  1. 如果父控件有顔色,也是自己需要的顔色,那麼就不必在子控件加背景顔色 。
  2. 如果每個自控件的顔色不太一樣,而且可以完全覆寫父控件,那麼就不需要再父控 件上加背景顔色。
  3. 盡量減少不必要的嵌套。
  4. 能用LinearLayout和FrameLayout,就不要用RelativeLayout,因為RelativeLayout控件相對比較複雜,測繪也想要耗時。

1.1、 include、merge 和 ViewStub 三兄弟

include 可以提高布局的複用性,大大友善我們的開發,有人說這個沒有減少布 局的嵌套吧,對,include 确實沒有,但是 include 和 merge 聯手搭配,效果那是杠杠滴。

merge 的布局取決于父控件是哪個布局,使用 merge 相當于減少了自身的一層布 局,直接采用父 include 的布局,當然直接在父布局裡面使用意義不大,是以會 和 include 配合使用,既增加了布局的複用性,用減少了一層布局嵌套。

ViewStub 它可以按需加載,什麼意思?用到他的時候喊他一下,再來加載,不需要的時候像空氣一樣,在一邊靜靜的呆着,不吃你的米,也不花你家的錢。等需 要的時候 ViewStub 中的布局才加載到記憶體,多節儉持家啊。對于一些進度條, 提示資訊等等八百年才用一次的功能,使用 ViewStub 是極其合适的。這就是不 用不知道,一用戒不了。

1.2、 ConstraintLayout

ConstraintLayout 可以有效地解決布局嵌套過多的問題。ConstraintLayout 使用限制的方式來指定各個控件的位置和關系的,它有點類似于 RelativeLayout,但遠比 RelativeLayout 要更強大(照抄隔壁 IOS 的限制布局)。是以簡單布局簡單處理, 複雜布局 ConstraintLayout 很好使,提升性能從布局做起。

2、繪制優化

我們把布局優化了,但是和布局息息相關的還有繪制,這是直接影響顯示的兩個根本因素。

我們平時感覺的卡頓問題最主要的原因之一是因為渲染性能,因為越來越複雜的 界面互動,其中可能添加了動畫,或者圖檔等等。我們希望創造出越來越炫的交 互界面,同時也希望他可以流暢顯示,但是往往卡頓就發生在這裡。

這個是 Android 的渲染機制造成的,Android 系統每隔 16ms 發出 VSYNC 信号, 觸發對 UI 進行渲染,但是渲染未必成功,如果成功了那麼代表一切順利,但是失敗了可能就要延誤時間,或者直接跳過去,給人視覺上的表現,就是要麼卡了 一會,要麼跳幀。

View 的繪制頻率保證 60fps 是最佳的,這就要求每幀繪制時間不超過 16ms(16ms = 1000/60),雖然程式很難保證 16ms 這個時間,但是盡量降低 onDraw 方法中的 複雜度總是切實有效的。

第一點:onDraw 方法中不要做耗時的任務,也不做過多的循環操作,特别是嵌 套循環,雖然每次循環耗時很小,但是大量的循環勢必霸占 CPU 的時間片,從 而造成 View 的繪制過程不流暢。

第二點:除了循環之外,onDraw()中不要建立新的局部對象,因為 onDraw()方 法一般都會頻繁大量調用,就意味着會産生大量的零時對象,不進占用過的記憶體, 而且會導緻系統更加頻繁的 GC,大大降低程式的執行速度和效率。

3、記憶體優化

記憶體洩漏指的是那些程式不再使用的對象無法被 GC 識别,這樣就導緻這個對象 一直留在記憶體當中,占用了沒來就不多的記憶體空間。

因為有記憶體洩漏,是以記憶體被占用越來越多,那麼 GC 會更容易被觸發,GC 會越 來越頻發,但是當 GC 的時候所有的線程都是暫停狀态的,需要處理的對象數量 越多耗時越長,是以這也會造成卡頓。

3.1、集合類洩漏

集合類添加元素後,仍引用着集合元素對象,導緻該集合中的元素對象無法被回 收,進而導緻記憶體洩露。

static List<Object> mList = new ArrayList<>();
for (int i = 0; i < 100; i++) { Object obj = new Object();
     mList.add(obj);
      obj = null;
}           

複制

當 mList 沒用的時候,我們如果不做處理的話,這就是典型的占着茅坑不拉屎, mList 内部持有者衆多集合元素的對象,不洩露天理難容啊。解決這個問題也超 級簡單。把 mList 清理掉,然後把它的引用也給釋放掉。

mList.clear();
mList = null;           

複制

3.2、 單例/靜态變量造成的記憶體洩漏

單例模式具有其靜态特性,它的生命周期等于應用程式的生命周期,正是因為這一點,往往很容易造成記憶體洩漏。 先來一個小栗子:

public class SingleInstance {
       private static SingleInstance mInstance; 
       private Context mContext;
       
       private SingleInstance(Context context){
              this.mContext = context;
       }
       
       public static SingleInstance newInstance(Context context){
              if(mInstance == null){
                     mInstance = new SingleInstance(context);
              }
              return sInstance;
       }
}           

複制

當我們在 Activity 裡面使用這個的時候,把我們 Acitivty 的 context 傳進去,那麼, 這個單例就持有這個 Activity 的引用,當這個 Activity 沒有用了,需要銷毀的時候, 因為這個單例還持有 Activity 的引用,是以無法 GC 回收,是以就出現了記憶體洩 漏,也就是生命周期長的持有了生命周期短的引用,造成了記憶體洩漏。

是以我們要做的就是生命周期長的和生命周期長的玩,短的和短的玩。

解決方案也很簡單:

public class SingleInstance {
    private static SingleInstance mInstance; 
    private Context mContext;
    
    private SingleInstance(Context context){
        this.mContext = context.getApplicationContext();
    }
    
    public static SingleInstance newInstance(Context context){
        if(mInstance == null){
            mInstance = new SingleInstance(context); }
            return sInstance;
        }
}           

複制

3.3、 匿名内部類/非靜态内部類

Android 性能優化最佳實踐什麼是性能優化1、布局優化2、繪制優化3、記憶體優化4、 啟動速度優化 5、包體優化6、 耗電優化 7、 ListView 和 Bitmap 優化 8、 響應速度優化 9、 線程優化 10、 微優化 結尾

這是一張寶圖

非靜态内部類他會持有他外部類的引用,從圖我們可以看到非靜态内部類的生命周期可能比外部類更長,這就是二樓的情況一緻了,如果非靜态内部類的周明周期長于外部類,在加上自動持有外部類的強引用,我的乖乖,想不洩漏都難啊。

舉個例子:

public class TestActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);
    new MyAscnyTask().execute(); 
  }
  
class MyAscnyTask extends AsyncTask<Void, Integer, String>{ 
  @Override
  protected String doInBackground(Void... params) { 
    try {
      Thread.sleep(100000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return ""; }
  }
}           

複制

我們經常會用這個方法去異步加載,然後更新資料。貌似很平常,我們開始學這 個的時候就是這麼寫的,沒發現有問題啊,但是你這麼想一想,MyAscnyTask 是 一個非靜态内部類,如果他處理資料的時間很長,極端點我們用 sleep 100 秒, 在這期間 Activity 可能早就關閉了,本來 Activity 的記憶體應該被回收的,但是我們 知道非靜态内部類會持有外部類的引用,是以 Activity 也需要陪着非靜态内部類 MyAscnyTask 一起天荒地老。好了,記憶體洩漏就形成了。

怎麼辦呢?

既然 MyAscnyTask 的生命周期可能比較長,那就把它變成靜态,和 Application 玩去吧,這樣 MyAscnyTask 就不會再持有外部類的引用了。兩者也互相獨立了。

static class MyAscnyTask extends AsyncTask<Void, Integer, String>{
  @Override
  protected String doInBackground(Void... params) { 
    try {
      Thread.sleep(100000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return ""; 
  }
}           

複制

說完非靜态内部類,我再來看看匿名内部類,這個問題很常見,匿名内部類和非 靜态内部類有一個共同的地方,就是會隻有外部類的強引用,是以這哥倆本質是 一樣的。但是處理方法有些不一樣。但是思路絕對一樣。換湯不換藥。

public class TestActivity extends Activity { 
  private TextView mText;
  private Handler mHandler = new Handler(){ 
    @Override
    public void handleMessage(Message msg) { 
      super.handleMessage(msg);
      mText.setText(" do someThing");
    } 
  };
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_test); 
   mText = findVIewById(R.id.mText);
   // 匿名線程持有 Activity 的引用,進行耗時操作 
   new Thread(new Runnable() {
     @Override
     public void run() { 
       try {
         Thread.sleep(100000);
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
     }
   }).start();
   
   mHandler. sendEmptyMessageDelayed(0, 100000); }           

複制

想必這兩個方法是我們經常用的吧,很熟悉,也是這麼學的,沒感覺不對啊,老 師就是這麼教的,通過我們上面的分析,還這麼想嗎?關鍵是 耗時時間過長, 造成内部類的生命周期大于外部類,對弈非靜态内部類,我們可以靜态化,至于 匿名内部類怎麼辦呢?一樣把它變成靜态内部類,也就是說盡量不要用匿名内部 類。完事了嗎?很多人不注意這麼一件事,如果我們在 handleMessage 方法裡進 行 UI 的更新,這個 Handler 靜态化了和 Activity 沒啥關系了,但是比如這個 mText, 怎麼說?全寫是 activity.mText,看到了吧,持有了 Activity 的引用,也就是說 Handler 費勁心思變成靜态類,自認為不持有 Activity 的引用了,準确的說是不自 動持有 Activity 的引用了,但是我們要做 UI 更新的時候勢必會持有 Activity 的引 用,靜态類持有非靜态類的引用,我們發現怎麼又開始記憶體洩漏了呢?處處是坑 啊,怎麼辦呢?我們這裡就要引出弱引用的概念了。

引用分為強引用,軟引用,弱引用,虛引用,強度一次遞減。

強引用 我們平時不做特殊處理的一般都是強引用,如果一個對象具有強引用,GC 甯可 OOM 也絕不會回收它。

軟引用(SoftReference) 如果記憶體空間足夠,GC 就不會回收它,如果記憶體空間不

弱引用(WeakReference) 弱引用要比軟引用,更弱一個級别,記憶體不夠要回收他, GC 的時候不管記憶體夠不夠也要回收他,簡直是弱的一匹。不過 GC 是一個優先級 很低的線程,也不是太頻繁進行,是以弱引用的生活還過得去,沒那麼提心吊膽。

虛引用 用的甚少,如果想了解的朋友,可以自行谷歌百度。

是以我們用弱引用來修飾 Activity,這樣 GC 的時候,該回收的也就回收了,不會再有記憶體洩漏了。

public class TestActivity extends Activity {
  private TextView mText;
  private MyHandler myHandler = new MyHandler(TestActivity.this); 
  private MyThread myThread = new MyThread();
  
  private static class MyThread extends Thread { 
    @Override
    public void run() { 
      super.run();
      try {
        sleep(100000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    } 
  }
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);
    mText = findViewById(R.id.mText); myHandler.sendEmptyMessageDelayed(0, 100000); 
    myThread.start();
  } 
  //最後清空這些回調
  @Override
  protected void onDestroy() { 
    super.onDestroy();
    myHandler.removeCallbacksAndMessages(null); 
  }
  
  private static class MyHandler extends Handler {
    //用弱引用持有Activity引用
    WeakReference<TestActivity> weakReference;
    MyHandler(TestActivity testActivity) { 
      this.weakReference = new WeakReference<TestActivity>(testActivity); 
    }
    
    @Override
    public void handleMessage(Message msg) {
      super.handleMessage(msg); weakReference.get().mText.setText("do someThing");
    }
  }
  
}           

複制

3.4、 資源未關閉造成的記憶體洩漏

  1. 網絡、檔案等流忘記關閉。
  2. 手動注冊廣播時,退出時忘記 unregisterReceiver()。
  3. Service 執行完後忘記 stopSelf() 。
  4. EventBus 等觀察者模式的架構忘記手動解除注冊。

這些需要記住又開就有關,具體做法也很簡單就不一一贅述了。給大家介紹幾個很好用的工具:

1、leakcanary 傻瓜式操作,哪裡有洩漏自動給你顯示出來,很 直接很暴力。

2、我們平時也要多使用 Memory Monitor 進行記憶體監控,這個分 析就有些難度了,可以上網搜一下具體怎麼使用。

3、Android Lint 它可以幫助 我們發現代碼機構 / 品質問題,同時提供一些解決方案,記憶體洩露的會飄黃, 用起來很友善,具體使用方法上網學習,這裡不多做說明了。

4、 啟動速度優化

4.1、 利用提前展示出來的 Window,快速展示出來一個界面

使用 Activity 的 windowBackground 主題屬性來為啟動的 Activity 提供一個簡單的 drawable。

Layout XML file:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" 
android:opacity="opaque">
  <item android:drawable="@android:color/white"/>
  <item>
   <bitmap android:src="@drawable/product_logo_144dp" 
           android:gravity="center"/>
  </item> 
</layer-list>           

複制

Manifest file:

<activity ... android:theme="@style/AppTheme.Launcher" />           

複制

這樣在啟動的時候,會先展示一個界面,這個界面就是 Manifest 中設定的 Style, 等 Activity 加載完畢後,再去加載 Activity 的界面,而在 Activity 的界面中,我們 将主題重新設定為正常的主題,進而産生一種快的感覺。其實就是個障眼法而已, 提前讓你看到了假的界面。也算是一種不錯的方法,但是治标不治本。

4.2、 避免在啟動時做密集沉重的初始化

我們審視一下我們的 MyApplication 裡面的操作。初始化操作有友盟,百度,bugly, 資料庫,IM,神策,圖檔加載庫,網絡請求庫,廣告 sdk,地圖,推送,等等, 這麼多需要初始化,Application 的任務太重了,啟動不慢才怪呢。

怎麼辦呢?這些還都是必要的,不能不去初始化啊,那就隻能異步加載了。但是 并不是所有的都可以進行異步處理。這裡分情況給出一些建議:

1、比如像友盟, bugly 這樣的業務非必要的可以的異步加載。

2、比如地圖,推送等,非第一時 間需要的可以在主線程做延時啟動。當程式已經啟動起來之後,在進行初始化。

3、對于圖檔,網絡請求架構必須在主線程裡初始化了。

同時因為我們一般會有閃屏頁面,也可以把延時啟動的地圖,推動的啟動在這個 時間段裡,這樣合理安排時間片的使用。極大的提高了啟動速度。

4.3、 避免 I/O 操作、反序列化、網絡操作、布局嵌套等。

這個不用多說了,大家應該知道如何去做了。

5、包體優化

我做過兩年的海外應用産品,深知包體大小對于産品新增的影響,包體小百分之 五,可能新增就增加百分之五。如果産品基數很大,這個提升就更可怕了。不管 怎麼說,我們要減肥,要六塊腹肌,不要九九歸一的大肚子。

既然要瘦身,那麼我們必須知道 APK 的檔案構成,解壓 apk:

Android 性能優化最佳實踐什麼是性能優化1、布局優化2、繪制優化3、記憶體優化4、 啟動速度優化 5、包體優化6、 耗電優化 7、 ListView 和 Bitmap 優化 8、 響應速度優化 9、 線程優化 10、 微優化 結尾

apk結構

assets 檔案夾 存放一些配置檔案、資源檔案,assets 不會自動生成對應的 ID, 而是通過 AssetManager 類的接口擷取。

res 目錄 res 是 resource 的縮寫,這個目錄存放資源檔案,會自動生成對應的 ID 并映射到 .R 檔案中,通路直接使用資源 ID。

META-INF 儲存應用的簽名資訊,簽名資訊可以驗證 APK 檔案的完整性。

AndroidManifest.xml 這個檔案用來描述 Android 應用的配置資訊,一些元件的注冊資訊、可使用權限等。

classes.dex Dalvik 位元組碼程式,讓 Dalvik 虛拟機可執行,一般情況下,Android 應 用在打包時通過 Android SDK 中的 dx 工具将 Java 位元組碼轉換為 Dalvik 位元組 碼。

resources.arsc 記錄着資源檔案和資源 ID 之間的映射關系,用來根據資源 ID 尋找資源。

我們需要從代碼和資源兩方面減少大小。

5.1、删除無用資源

首先我們可以使用 lint 工具,如果有沒有使用過的資源就會列印如下的資訊(不會使用的朋友可以上網看一下)。

res/layout/preferences.xml: Warning: The resource R.layout.preferences appears
to be unused [UnusedResources]           

複制

同時我們可以開啟資源壓縮,自動删除無用的資源

android { ...
   buildTypes {
       release {
shrinkResources true minifyEnabled true proguardFiles
getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }           

複制

5.2、動态繪制圖像

我們可以使用可繪制對象,某些圖像不需要靜态圖像資源;架構可以在運作時動态繪制圖像。Drawable 對象(<shape>以 XML 格式)可以占用 APK 中的少量空 間。此外,XML Drawable 對象産生符合材料設計準則的單色圖像。

上面的話官方,簡單說來就是,能自己用 XML 寫 Drawable,就自己寫,能不用 公司的 UI 切圖,就别和他們說話,咱們自己造,做自己的 UI,美滋滋。而且這 種圖檔占用空間會很小。

5.3、重用資源

第一點:重用資源,比如一個三角按鈕,點選前三角朝上代表收起的意思,點選後三 角朝下,代表展開,一般情況下,我們會用兩張圖來切換。但是,我們完全可以用旋轉的形式去改變 。

第二點:同一圖像的着色不同,我們可以用 android:tint 和 tintMode 屬性,低版本(5.0 以下)可以使用 ColorFilter。

5.4、資源壓縮

壓縮 PNG 和 JPEG 檔案可以減少 PNG 檔案的大小,而不會丢失圖像品質。您可以使用這些工具: pngcrush,pngquant,或 zopflipng。所有這些工具都可以減少 PNG 文 件的大小,同時保持感覺的圖像品質。

5.5、 使用 WebP 檔案格式

使用 WebP 檔案格式 可以使用圖像的 WebP 檔案格式,而不是使用 PNG 或 JPEG 檔案。WebP 格式提供有損壓縮(如 JPEG)以及透明度(如 PNG),但可 以提供比 JPEG 或 PNG 更好的壓縮。

可以使用 Android Studio 将現有的 BMP,JPG,PNG 或靜态 GIF 圖像轉換為 WebP 格式。

5.6、 使用矢量圖形

使用矢量圖形 可以使用矢量圖形來建立與分辨率無關的圖示和其他可伸縮 Image。使用這些圖形可以大大減少 APK 大小。一個 100 位元組的檔案可以生成與 螢幕大小相關的清晰圖像。

但是,系統渲染每個 VectorDrawable 對象需要花費大量時間 ,而較大的圖像需要更長的時間才能顯示在螢幕上。是以,請考慮僅在顯示小圖像時使用這些矢量 圖形。

不要把 AnimationDrawable 用于建立逐幀動畫,因為這樣做需要為動畫的每個幀包含一個單獨的位圖檔案,這會大大增加 APK 的大小。

5.7、 代碼混淆

代碼混淆 使用 proGuard 代碼混淆器工具,它包括壓縮、優化、混淆等功能。 這個大家太熟悉了。不多說了。

android {
   buildTypes {
     release {
       minifyEnabled true proguardFiles
       getDefaultProguardFile(‘proguard-android.txt'),
     } 
   }
}           

複制

5.8、 插件化

功能子產品放在伺服器上,按需下載下傳,可以減少安裝包大小。

6、 耗電優化

谷歌推薦使用 JobScheduler,來調整任務優先級等政策來達到降低損耗的目的。 JobScheduler 可以避免頻繁的喚醒硬體子產品,造成不必要的電量消耗。避免在不 合适的時間(例如低電量情況下、弱網絡或者移動網絡情況下的)執行過多的任務 消耗電量。

具體功能:

1、可以推遲的非面向使用者的任務(如定期資料庫資料更新);

2、當充電時才希望執行的工作(如備份資料);

3、需要通路網絡或 Wi-Fi 連接配接的任務 (如向伺服器拉取配置資料);

4、零散任務合并到一個批次去定期運作;

5、當裝置空閑時啟動某些任務;

6、隻有當條件得到滿足, 系統才會啟動計劃中的任 務(充電、WIFI...);

同時谷歌針對耗電優化也提出了一個懶惰第一的法則:

減少:你的應用程式可以删除備援操作嗎?例如,它是否可以緩存下載下傳的資料而不是重複喚醒無線電以重新下載下傳資料?

推遲:應用是否需要立即執行操作?例如,它可以等到裝置充電才能将資料備份到雲端嗎?

合并:可以批處理工作,而不是多次将裝置置于活動狀态嗎?例如,幾十個應用 程式是否真的有必要在不同時間打開收音機發送郵件?在一次喚醒收音機期間, 是否可以傳輸消息?

谷歌在耗電優化這方面确實顯得有些無力,希望以後可以退出更好的工具和解決 方案,不然這方面的優化優先級還是很低。付出和回報所差太大。

7、 ListView 和 Bitmap 優化

針對 ListView 優化,主要是合理使用 ViewHolder。建立一個内部類 ViewHolder, 裡面的成員變量和 view 中所包含的元件個數、類型相同,在 convertview 為 null 的時候,把 findviewbyId 找到的控件賦給 ViewHolder 中對應的變量,就相當于先 把它們裝進一個容器,下次要用的時候,直接從容器中擷取。

現在我們現在一般使用 RecyclerView,自帶這個優化,不過還是要了解一下原理 的好。 然後可以對接受來的資料進行分段或者分頁加載,也可以優化性能。

Bitmap 的優化套路很簡單,粗暴,就是讓壓縮。 三種壓縮方式:

1.對圖檔品質 進行壓縮

2.對圖檔尺寸進行壓縮

3.使用 libjpeg.so 庫進行壓縮

使用 libjpeg.so 庫進行壓縮 可以參考這篇 Android 性能優化系列之 Bitmap 圖檔 優化: https://blog.csdn.net/u012124438/article/details/66087785)

8、 響應速度優化

影響響應速度的主要因素是主線程有耗時操作,影響了響應速度。是以響應速度 優化的核心思想是避免在主線程中做耗時操作,把耗時操作異步處理。

9、 線程優化

線程優化的思想是采用線程池,避免在程式中存在大量的 Thread。線程池可以 重用内部的線程,進而避免了現場的建立和銷毀所帶來的性能開銷,同時線程池 還能有效地控制線程池的最大并發數,避免大量的線程因互相搶占系統資源進而 導緻阻塞現象發生。

《Android 開發藝術探索》對線程池的講解很詳細,不熟悉線程池的可以去了解 一下。

優點:

1、減少在建立和銷毀線程上所花的時間以及系統資源的開銷。

2、 如不使用線程池,有可能造成系統建立大量線程而導緻消耗完系統記憶體以 及”過度切換”。

需要注意的是:

1、如果線程池中的數量未達到核心線程的數量,則直接會啟動一個核心線程來執行任務。

2、如果線程池中的數量已經達到 或超過核心線程的數量,則任務會被插入到任務隊列中标等待執

行。

3、如果(2)中的任務無法插入到任務隊列中,由于任務隊列已滿, 這時候如果線程數量未達到線程池規定最大值,則會啟動一個非核心線程 來執行任務。

4、如果(3)中線程數量已經達到線程池最大值,則會拒 絕執行此任務,ThreadPoolExecutor 會調用 RejectedExecutionHandler 的 rejectedExecution 方法通知調用者。

10、 微優化

這些微優化可以在組合時提高整體應用程式性能,但這些更改不太可能導緻顯着的性能影響。選擇正确的算法和資料結構應始終是我們的首要任務,以提高代碼效率。

編寫高效代碼有兩個基本規則: 1、不要做你不需要做的工作;2、如果可以避免,請不要配置設定記憶體

具體有幾條建議:

1、避免建立不必要的對象。對象建立永遠不是免費的,雖然每一個的代價不是很大,但是總歸是有代價的不是嗎?能不建立何必要浪費資源呢?

2、首選靜态(這裡說的是特定情景) 。如果您不需要通路對象的字段,請使您的方法保持靜态。調用速度将提高約 15%-20%。這也是很好的做法,因為你可以從方法簽名中看出,調用方法不能改變對象的狀态。

3、對常量使用 static final。此優化僅适用于基本類型和 String 常量,而不适用于 任 意引用類型。盡管如此,static final 盡可能聲明常量是一種好習慣。

4、使用增強的 for 循環文法。增強 for 循環(for-each)可用于實作 Iterable 接口 和數組的集合。

5、避免使用浮點數。根據經驗,浮點數比 Android 裝置上的整數慢約 2 倍 。

結尾

本文篇幅有限,性能優化的方面很多,每一項深入下去,不寫個幾十萬字是結束 不了,是以很多都是淺嘗辄止,希望可以抛磚引玉,用我的拙劣的文章,給大家 一些幫助。性能優化需要走的路還很遠,希望能和各位同學一同前行,一起進步。

參考: Android APP 性能優化的一些思考 https://www.cnblogs.com/cr330326/p/8011523.html

谷歌官方 http://developer.android.com/topic/performance/ Android 性能優化系列之 Bitmap 圖檔優化

https://blog.csdn.net/u012124438/article/details/66087785 Android 記憶體洩漏總結 https://yq.aliyun.com/articles/3009

作者:玉剛說 連結:https://juejin.im/post/5b50b017f265da0f7b2f649c