1. 程式人生 > >Android優化方案

Android優化方案

一,圖片優化

1,圖片載入的框架有,UniversalImageLoader,Picasso,Glide,Fresco。

UniversalImageLoader:本人開發最早使用的框架是UniversalImageLoader,然而這個框架已經過時。雖然這個框架對於記憶體佔用做了一些處理,但是並非完全滿足我們的需求,對於載入大圖長圖圖片過多的情況下還是很佔記憶體。並且這個框架配置比較繁瑣。之前在平板上做過一個頁面,這個頁面需要顯示大圖,圖片鋪滿整個螢幕,平板螢幕本來就很大,在加上圖片還很多,用此框架自測很容易發生記憶體溢位,隨便一點記憶體就能過100MB。

Picasso:這裡不再過多介紹。

Glide:Glide是基於Picasso開發的一個框架,也是Google 推薦的一個框架。並且它支援gif動圖,包也很小,使用起來很方便。不過這裡要注意,這裡的gif動圖支援並不是非常好。如果你需要展示的動圖比較多,並且動圖還很大,那麼建議用Fresco。本人就遇到過這樣扯淡的需求,在平板上顯示動圖,圖片大而且還多,整個頁面都是動圖。有關Glide的使用可以看這幾篇文章

Fresco:這個框架是Facebook出的,這個框架的出色之處可以適配低端手機。它的快取策略另闢蹊徑,沒有在 Java 層處理,直接在更底層的 Native 堆做手腳。於是 Fresco 將圖片放到一個特別的記憶體區域叫 Ashmem 區,就是屬於 Native 堆,圖片將不再佔用 App 的記憶體,Java 層對此無能為力,這裡是屬於 C++ 的地盤,所以能大大的減少 OOM。但是Fresco庫比較大,支援的多,會使我們app包增加1MB多。還有一個問題需要注意,有一種低端機,如果使用了Fresco框架,並且你的應用是系統應用,那麼會導致圖片載入不出來。解決方法就是單獨把Fresco相關so檔案拷貝到系統目錄下。

二,過度繪製優化

1,過度繪製就是螢幕上的某個畫素在同一幀的時間內被多次繪製。在什麼情況下會出現過度繪製?。如果你在xml中使用了多層巢狀的佈局,有些佈局是不需要顯示的,那麼這樣就會導致過度繪製。過度繪製會浪費大量cpu資源。

2,主要優化點

①,在開發中儘量不要使用多層巢狀的佈局,儘量去掉沒用的背景色和背景圖。

 getWindow().setBackgroundDrawable(null);

<style name="AppTheme" parent="android:Theme.Light.NoTitleBar">
    <item name="android:windowBackground">@null</item>
</style>

②,如果你使用了自定義控制元件,使用Canvas的clipRect和clipPath方法限制View的繪製區域

③,重疊view
使用ViewStub來載入一些不常用的佈局,它是一個輕量級且預設不可見的檢視,可以動態的載入一個佈局,只有你用到這個重疊著的view的時候才載入,推遲載入的時間。

④,儘量使用LinearLayout和RelativeLayout,在層級相同的情況下,儘量用LinearLayout替代RelativeLayout

⑤,使用include把可複用佈局單獨拿出來

三,資料庫優化

1,這裡介紹幾個資料庫框架

①,greenDao:GreenDao是為Android設計的物件關係對映(ORM)工具。它提供了物件到關係型資料庫SQLite的相應介面。為了在Android工程中使用greenDao,需要建立另一個“生成器”工程,它的任務是在你的工程域裡生成具體的程式碼。因此相比與其它ORM框架具有出眾效能。

②,LitePal:LitePal是物件關係對映(ORM)模型。它使開發者使用SQLite資料庫變得非常容易。 你可以不用寫一句SQL語句就可以完成大部分資料庫操作,包括建立表,更新表,約束操作,聚合功能等等。

③,ORMLite:(Object Relational Mapping Lite)提供了一些輕量級持久化Java物件到SQL資料庫,同時也避免了複雜性和更多的標準的ORM包的開銷功能。它支援的SQL資料庫使用JDBC的數量,還支援原生的Android作業系統資料庫API呼叫sqlite。

④,xutils:xutils中不單是資料庫框架,是一個整合框架,其中包含資料庫模組

2,這裡無論使用哪種框架,對於我們應用本身來說都是好的。我們只需要注意資料庫的操作是耗時的,應該放在子執行緒中去執行。

四,記憶體洩漏優化

記憶體洩漏我們通常會考慮到圖片載入,然而圖片載入只是一部分。開發者過程中比如以下場景

1,靜態變數導致的記憶體洩漏,mContext為靜態變數,會導致activity無法正常銷燬。

public class MainActivity extends AppCompatActivity {
    private static Context mContext;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext=this;
    }
}

2,單例模式導致的記憶體洩漏

//單例類
public class TestManager {
    private List<OnDataArrivedListener> mOnDataArrivedListeners = new ArrayList<>();

    private static class SingletonHolder {
        public static final TestManager testManager = new TestManager();
    }

    public static TestManager getInstance() {
        return SingletonHolder.testManager;
    }

    public synchronized void registerListener(OnDataArrivedListener listener) {
        if (!mOnDataArrivedListeners.contains(listener)) {
            mOnDataArrivedListeners.add(listener);
        }
    }

    public synchronized void unRegisterListener(OnDataArrivedListener listener) {
        mOnDataArrivedListeners.remove(listener);
    }

    public interface OnDataArrivedListener {
        public void onDataArrived(Object data);
    }
}
 //在activity中呼叫
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext=this;
        TestManager.getInstance().registerListener(this);
    }

讓activity實現OnDataArrivedListener介面註冊監聽,因為TestManager是單例的,所持有的生命週期長,導致activity物件無法及時釋放。

3,屬性動畫導致的記憶體洩漏

我們在專案中如果使用了動畫,特別是一些無限迴圈的動畫,一定要在acitivty的onDestroy方法中及時結束動畫。

4,小結

  • 避免建立過多的物件
  • 不要過多的使用列舉,列舉佔用的空間要比整數大
  • 常量使用 static final 來修飾
  • 使用一些Android特有的資料結構,如 SparesArray和Pair等。
  • 適當使用軟引用和弱引用
  • 採用記憶體快取和磁碟快取
  • 儘量採用靜態內部類,這樣可以避免潛在得到由於內部類而導致的記憶體洩漏