一、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記憶體分析工具,找出引起記憶體沒有釋放的原因
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN0LclHdpZXYyd2LcBzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX9MWbiZHeyoVdsdkYuh3RhZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jN3UjNyYDM1EjNwEDM1EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
發現是context沒有釋放,導緻記憶體洩露,繼續分析,找到沒有引起GC的保持該引用的地方
找到最短的GC path,發現是Volley中德CacheDispacher保持了context的引用,導緻沒有引起GC釋放記憶體。
但是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記憶體分析工具的使用方法。