凌空请求的匿名侦听器导致内存泄漏

Har*_*hta 7 android memory-leaks web-services android-volley leakcanary

我正在使用排球库进行网络服务调用.我创建了一个通用类,用于调用所有Web服务并从那里进行服务调用,并为成功和错误响应提供匿名侦听器.

但是当我使用泄漏金丝雀时,它显示出与上下文相关的内存泄漏.以下是我的代码片段:

public void sendRequest(final int url, final Context context, final ResponseListener responseListener, final Map<String, String> params) {
    StringRequest stringRequest;
    if (isNetworkAvailable(context)) {

      stringRequest = new StringRequest(methodType, actualURL + appendUrl, new Listener<String>() {
            @Override
            public void onResponse(String response) {
                dismissProgressDialog(context);
                try {
                    (responseListener).onResponse(url, response);
                } catch (JsonSyntaxException e) {
                    // Util.showToast(context, context.getResources().getString(R.string.error));
                    Crashlytics.logException(e);
                }
            }

        }, new ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // Util.showToast(context,context.getString(R.string.error));

                dismissProgressDialog(context);
                if (error instanceof NetworkError) {
                     Util.showToast(context, context.getResources().getString(R.string.network_error));
                } else if (error instanceof NoConnectionError) {
                     Util.showToast(context, context.getResources().getString(R.string.server_error));
                } else if (error instanceof TimeoutError) {
                     Util.showToast(context, context.getResources().getString(R.string.timeout_error));
                } else {
                     Util.showToast(context, context.getResources().getString(R.string.default_error));
                }


            }

        }) {
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                return params;
            }


            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                return request.getHeaders(context, actualURL, false);
            }
        };
        stringRequest.setRetryPolicy(new DefaultRetryPolicy(30000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        VolleySingleton.getInstance(context).addRequest(stringRequest);
    } else {
         Util.showToast(context, context.getString(R.string.internet_error_message));
    }
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个名为响应侦听器的接口,用于重定向对活动或片段的响应.我提出如下要求.

Request.getRequest().sendRequest(Request.SOME URL, SplashScreenActivity.this, SplashScreenActivity.this, new HashMap<String, String>());
Run Code Online (Sandbox Code Playgroud)

但我面临内存泄漏:

In 2.1.1:31.
* activity.SplashScreenActivity has leaked:
* GC ROOT com.android.volley.NetworkDispatcher.<Java Local>
* references network.Request$5.mListener (anonymous subclass of com.android.volley.toolbox.StringRequest)
* references network.Request$3.val$responseListener (anonymous implementation of com.android.volley.Response$Listener)
* leaks activity.SplashScreenActivity instance
* Retaining: 1.2MB.
* Reference Key: b8e318ea-448c-454d-9698-6f2d1afede1e
* Device: samsung samsung SM-G355H kanas3gxx
* Android Version: 4.4.2 API: 19 LeakCanary: 1.4 6b04880
* Durations: watch=5052ms, gc=449ms, heap dump=2617ms, analysis=143058ms
Run Code Online (Sandbox Code Playgroud)

任何想法删除此泄漏任何帮助表示赞赏.

Bob*_*Bob 5

通常,匿名类对封闭的类实例有很强的引用。您的情况就是SplashScreenActivity。现在,我想您Activity已经完成了,然后才能通过Volley从服务器获得响应。由于侦听器对封装Activity有很强的引用,因此在Anonymous类完成之前,无法垃圾回收该Activity。您应该做的是使用Activity实例标记要发送的所有请求,并在onDestroy()Activity的回调中取消所有请求。

stringRequest.setTag(activityInstance);
Run Code Online (Sandbox Code Playgroud)

要取消所有待处理的请求:

requestQueue.cancellAll(activityInstance);
Run Code Online (Sandbox Code Playgroud)

另外,在VolleySingleton内部使用Application上下文创建RequestQueue。

mRequestQueue = Volley.newRequestQueue(applicationContext);
Run Code Online (Sandbox Code Playgroud)

不要在此处使用Activity上下文,也不要在VolleySingleton中缓存您的Activity实例。


Nay*_*ava 2

基本上,匿名方法在您没有大量内存的地方Android或任何地方都很糟糕。ClientSideSystem发生的情况是,您已Context作为方法中的参数传递并anonymous保存它的引用。现在真正的混乱出现在场景中,当 make 内部的线程network call无法完成其工作并且在此之前调用活动由于某种原因销毁或回收时,在这种情况下GC无法收集该活动,因为wokerThread可能仍保留对其的引用。请仔细阅读此内容以获取详细说明。

解决方案可以是静态内部类或独立类,在这两种情况下都用于WeakReference保存资源并在使用它们之前进行空检查。

优点是如果没有其他人持有该对象的引用,WeakReference它将允许收集该对象。GC