前兩天用leakcanary檢查自己做的應(yīng)用時挨厚,發(fā)現(xiàn)居然報內(nèi)存泄漏的錯誤拟逮,而且內(nèi)存泄漏出現(xiàn)的原因是由于Volley使
用的問題,查看leakcanary打出的Log發(fā)現(xiàn)是由于Volley中的Listener導(dǎo)致赂蠢,這讓我很疑惑,為什么開源的框架Volley怎么會出現(xiàn)內(nèi)存泄漏這種問題纳猫。
在網(wǎng)上搜索了一下相關(guān)問題,發(fā)現(xiàn)出現(xiàn)這種問題的人還真不少竹捉,解決的方法也有很多種芜辕,列舉一下我查到的解決方法:
1.升級Volley包,有一個博客說將Volley的jar包升級一下版本(感覺不靠譜块差,沒有試)
2.使用單例模式侵续,使用ApplicationContext,我看了一下我的代碼,發(fā)現(xiàn)我用的就是單例模式憨闰,在Application中初始化RequestQueue状蜗,所以這種方法不能解決我的問題。
3.重點(diǎn):
在一篇關(guān)于這個問題討論的帖子中我發(fā)現(xiàn)了一條評論鹉动,感覺他說的很有道理轧坎,這個人的評論是這樣的:
我覺得,樓上回復(fù)的都不是重點(diǎn)泽示!Queue 用單例來封裝是對的缸血,但是內(nèi)存泄漏明顯不是因?yàn)槭遣皇菃卫蛟斐傻模且驗(yàn)闃侵鲗懙?new Response.Listener<String>() 這句使用了內(nèi)部匿名類械筛,因?yàn)樗跏蓟臅r候是在HeapTestActivity 里面自動生成一個內(nèi)部類捎泻,那么這個內(nèi)部類沒有執(zhí)行完畢的時候,是持有HeapTestActivity 的引用的埋哟,導(dǎo)致HeapTestActivity 不能被回收笆豁,從而導(dǎo)致內(nèi)存泄漏!
分析:
我感覺這個人的解釋我很贊同赤赊,內(nèi)存泄漏很大一部分出現(xiàn)的原因就是因?yàn)槟涿麅?nèi)部類持有外部類的引用導(dǎo)致渔呵,外部類不能被垃圾回收器回收,所以導(dǎo)致內(nèi)存泄漏砍鸠。在這個例子里面,因?yàn)閂olley使用的GsonRequest執(zhí)行的是網(wǎng)絡(luò)操作耕驰,Android中網(wǎng)絡(luò)操作和UI線程是異步的爷辱,所以,可能在網(wǎng)絡(luò)操作中朦肘,由于耗時操作沒有執(zhí)行完畢饭弓,導(dǎo)致Listener持有的Activity實(shí)例不能被銷毀,而導(dǎo)致內(nèi)存泄漏媒抠。
解決方式:
既然是由于Listener持有Activity的引用導(dǎo)致Activity不能被及時銷毀弟断,那么就要用到JAVA的四種引用中的WeakReference了,這個解決方式的是我收到的一篇博客趴生,原文鏈接阀趴,其實(shí)思想很簡單昏翰,就是實(shí)現(xiàn)以下Volley中的Listener和ErrorListener接口,在其中使用WeakReference在初始化Listener中持有Activity的引用刘急,這樣就可以解決Volley中內(nèi)存泄漏的問題了
(實(shí)測原來的內(nèi)存泄漏沒有了)
為了便于方便棚菊,我將郭神提供的GsonRequset二次封裝了一下,方便下次使用叔汁。
public class GsonRequest<T> extends Request<T> {
private final Response.Listener<T> mListener;
private Gson mGson;
private Class<T> mClass;
public GsonRequest(int method, String url, Class<T> clazz, WeakListener<T> listener,
WeakErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
mClass = clazz;
mListener = listener;
}
public GsonRequest(String url, Class<T> clazz, WeakListener<T> listener,
WeakErrorListener errorListener) {
this(Method.GET, url, clazz, listener, errorListener);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(mGson.fromJson(jsonString, mClass),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
public static abstract class WeakListener<T> implements Response.Listener<T> {
private final WeakReference<Activity> activityWeakReference;
public WeakListener(Activity activity) {
activityWeakReference = new WeakReference<Activity>(activity);
}
@Override
public abstract void onResponse(T response);
}
public static abstract class WeakErrorListener implements Response.ErrorListener {
private final WeakReference<Activity> activityWeakReference;
public WeakErrorListener(Activity activity) {
activityWeakReference = new WeakReference<Activity>(activity);
}
@Override
public abstract void onErrorResponse(VolleyError error);
}
}