天天看點

Andorid Volley架構加載圖檔OOM問題分析

一、Volley架構簡介

在這之前,我們在程式中需要和網絡通信的時候,大體使用的東西莫過于AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,Google 在2013年的I/O大會 上,釋出了Volley。Volley是Android平台上的網絡通信庫,能使網絡通信更快,更簡單,更健壯。

Volley提供了JsonObjectRequest、JsonArrayRequestStringRequest等Request形式

JsonObjectRequest:傳回JSON對象

JsonArrayRequest:傳回JsonArray。

StringRequest:傳回String,這樣可以自己處理資料,更加靈活

另外可以繼承自定義Request。

二、VOlley引起的OOM項目中用到Volley下載下傳網絡圖檔,在回調中擷取到bitmap做相應地操作。

       ImageRequest imageRequest = new ImageRequest(url+"--"+ bmWidth+"x"+bmWidth+".png",                new Response.Listener<Bitmap>() {                    @Override                    public void onResponse(Bitmap response) {                        initViewWithBitmap(response);                    }                }, 0, 0, Bitmap.Config.RGB_565, getImageError);        mQueue.add(imageRequest);

起初發現在這個界面操作偶先強關問題,抓到log看下是 outofmemory引起的。

由于該界面用到bitmap的地方比較多,是以在onDestoy()方法中手動釋放bitmap。

用記憶體檢視器觀察該界面的記憶體情況,發現每次進入退出後,記憶體并沒有完全釋放,大概每次都來6M左右

三、問題分析

工具:MAT記憶體分析工具

用MAT記憶體分析工具,找出引起記憶體沒有釋放的原因

Andorid Volley架構加載圖檔OOM問題分析

發現是context沒有釋放,導緻記憶體洩露,繼續分析,找到沒有引起GC的保持該引用的地方

Andorid Volley架構加載圖檔OOM問題分析

找到最短的GC path,發現是Volley中德CacheDispacher保持了context的引用,導緻沒有引起GC釋放記憶體。

Andorid Volley架構加載圖檔OOM問題分析

但是volley架構内的東西怎麼會引起這種問題?

首先想到在onDestroy中取消掉沒有加載完的request。但是沒有效果

google 了半天,終于在stackoverflow上找到了答案,大概的意思就是說,初始化RequestQueue的時候盡量使用全局的Context也就是ApplicationContext。

否則的話沒有Activity都要維護一個volley請求隊列以及分發線程、請求線程和緩存線程。

這樣就會導緻,在volley架構的内部保持了一個Activity的context引用,也就是說,當我們的Activity的生命周期結束了之後,volley中可能還有沒走完的子線程中依然保留該context的引用,導緻無法記憶體回收。

四、解決方法

首先,我們要保持項目中唯一一個Volley的RequestQueue,使用單例模式來實作

public class SingleRequestQueue {

private static RequestQueue mQueue;

    private SingleRequestQueue(Context context) {
        mQueue = Volley.newRequestQueue(context);
    }

    public static synchronized RequestQueue getRequestQueue(Context context){
        if (mQueue == null){
            new SingleRequestQueue(context.getApplicationContext());
        }
        return mQueue;
    }
}
           

在統一一個類中處理網絡請求。

另外,看到網上評論說當加載大的網絡圖檔的時候不建議使用Volley,我用的是UniversalImageLoader。

推薦一篇文章講解Android 中Context。點這裡

總結:

之前一直沒有遇到context上下文記憶體洩露的問題,這個問題很好地彌補了這方面的空白

通過這個問題的分析解決,加深了記憶體洩露的分析思路,同時也鞏固了MAT記憶體分析工具的使用方法。

繼續閱讀