天天看點

Volley的引用導緻記憶體洩漏Volley的引用導緻記憶體洩漏

Volley的引用導緻記憶體洩漏

  前兩天用leakcanary檢查自己做的應用時,發現居然報記憶體洩漏的錯誤,而且記憶體洩漏出現的原因是由于Volley使

用的問題,檢視leakcanary打出的Log發現是由于Volley中的Listener導緻,這讓我很疑惑,為什麼開源的架構Volley怎麼會出現記憶體洩漏這種問題。

  在網上搜尋了一下相關問題,發現出現這種問題的人還真不少,解決的方法也有很多種,列舉一下我查到的解決方法:

1.更新Volley包,有一個部落格說将Volley的jar包更新一下版本(感覺不靠譜,沒有試)

2.使用單例模式,使用ApplicationContext,我看了一下我的代碼,發現我用的就是單例模式,在Application中初始化RequestQueue,是以這種方法不能解決我的問題。

3.重點:

在一篇關于這個問題讨論的文章中我發現了一條評論,感覺他說的很有道理,這個人的評論是這樣的:

我覺得,樓上回複的都不是重點!Queue 用單例來封裝是對的,但是記憶體洩漏明顯不是因為是不是單例原因造成的,是因為樓主寫的 new Response.Listener() 這句使用了内部匿名類,因為他初始化的時候是在HeapTestActivity 裡面自動生成一個内部類,那麼這個内部類沒有執行完畢的時候,是持有HeapTestActivity 的引用的,導緻HeapTestActivity 不能被回收,進而導緻記憶體洩漏!

分析:

我感覺這個人的解釋我很贊同,記憶體洩漏很大一部分出現的原因就是因為匿名内部類持有外部類的引用導緻,外部類不能被垃圾回收器回收,是以導緻記憶體洩漏。在這個例子裡面,因為Volley使用的GsonRequest執行的是網絡操作,Android中網絡操作和UI線程是異步的,是以,可能在網絡操作中,由于耗時操作沒有執行完畢,導緻Listener持有的Activity執行個體不能被銷毀,而導緻記憶體洩漏。

解決方式:

既然是由于Listener持有Activity的引用導緻Activity不能被及時銷毀,那麼就要用到JAVA的四種引用中的WeakReference了,這個解決方式的是我收到的一篇部落格,原文連結,其實思想很簡單,就是實作以下Volley中的Listener和ErrorListener接口,在其中使用WeakReference在初始化Listener中持有Activity的引用,這樣就可以解決Volley中記憶體洩漏的問題了

(實測原來的記憶體洩漏沒有了)

為了便于友善,我将郭神提供的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);
    }

}