volley静态回调侦听器上下文gced

knsnq2tg  于 2021-07-13  发布在  Java
关注(0)|答案(2)|浏览(377)

在使用leakcanary之后,我发现我的应用程序中有很多漏洞,大多数都是由于volley的匿名回调侦听器造成的。所以我写了一个util(下面)类,它使用静态回调和 WeakReference 参考 Context 还有匿名回电。但是,当我第一次打开应用程序时,即冷启动,在请求发出后不久,上下文就会被gced,但在热启动期间,一切正常。同样,这只发生在应用程序中的第一个活动中。
任何处理内存泄漏的替代方法都是受欢迎的。

public abstract class VUtil {

    public static final String TAG = VUtil.class.getSimpleName();

    public interface JsonCallback {
        void onSuccess(JSONObject response);
    }

    public interface StringCallback {
        void onSuccess(String response);
    }

    public interface ErrorCallback {
        void onError(VolleyError error);
    }

    public static class JsonResponseListener implements Response.Listener<JSONObject> {
        private final WeakReference<Context> mContextWeakReference;
        private final WeakReference<JsonCallback> mCallbackWeakReference;

        public JsonResponseListener(Context context, JsonCallback callback) {
            mContextWeakReference = new WeakReference<>(context);
            mCallbackWeakReference = new WeakReference<>(callback);
        }

        @Override
        public void onResponse(JSONObject jsonObject) {
            Context context = mContextWeakReference.get();
            JsonCallback callback = mCallbackWeakReference.get();
            if (context != null && callback != null) {
                callback.onSuccess(jsonObject);
            } else {
                Log.d(TAG, "Context was GCed");
            }
        }
    }

    public static class StringResponseListener implements Response.Listener<String> {
        private final WeakReference<Context> mContextWeakReference;
        private final WeakReference<StringCallback> mCallbackWeakReference;

        public StringResponseListener(Context context, StringCallback callback) {
            mContextWeakReference = new WeakReference<>(context);
            mCallbackWeakReference = new WeakReference<>(callback);
        }

        @Override
        public void onResponse(String response) {
            Context context = mContextWeakReference.get();
            StringCallback callback = mCallbackWeakReference.get();
            if (context != null && callback != null) {
                callback.onSuccess(response);
            } else {
                Log.d(TAG, "Context was GCed");
            }
        }
    }

    public static class ErrorListener implements Response.ErrorListener {

        private final WeakReference<Context> mContextWeakReference;
        private final WeakReference<ErrorCallback> mCallbackWeakReference;

        public ErrorListener(Context context, ErrorCallback callback) {
            mContextWeakReference = new WeakReference<>(context);
            mCallbackWeakReference = new WeakReference<>(callback);
        }

        @Override
        public void onErrorResponse(VolleyError error) {
            Context context = mContextWeakReference.get();
            ErrorCallback callback = mCallbackWeakReference.get();
            if (context != null && callback != null) {
                callback.onError(error);
            } else {
                Log.d(TAG, "Context was GCed");
            }
        }
    }
}
b4wnujal

b4wnujal1#

gc依赖于正在发生的许多事情。造成这种情况的一个可能原因是,当你在“冷启动”后执行第一个请求时,你的应用程序必须初始化各种自定义对象、片段、活动、视图缓存等,因此在增加堆之前需要内存,从而执行gc。
不过,我建议的解决方案是更改您的体系结构。
1) 似乎你一直引用上下文,但它从来没有被使用过。放下它
2) 你有凌空的回调,委托给你的自定义回调,你需要通过无论如何,为什么不你简单地使用一套回调,你传递给各自的请求。
3) 你有自己的习惯性回电,但你不能没有它们。周引用并不是解决内存泄漏的最终方法。你必须弄清楚为什么裁判在你不需要的时候还在那里。
因此,如果泄漏问题出现在jsoncallback中,那么stringcallback和errorcallback实现只需尝试解决这个问题,而不是让链变长并在最后切断它。

xsuvu9jc

xsuvu9jc2#

多亏乔乔的回答帮助我找到了解决办法
始终使用 addToRequestQueue(request, TAG) . 在这里 TAG bit是当请求的活动/片段/视图或任何内容被gced时,我们用来取消它们的请求
我所做的是创建一个基本活动,并在该活动中添加所有请求取消代码。下面是它的样子

public abstract class BaseActivity extends AppCompatActivity {

    public final String tag;

    public BaseActivity() {
        super();
        tag = getClass().getSimpleName();
    }

    @Override
    protected void onDestroy() {
        App.getInstance().cancelRequests(tag);
        super.onDestroy();
    }

    protected <T> void addToRequestQueue(Request<T> request) {
        App.getInstance().addToRequestQueue(request, tag);
    }

}
``` `cancelRequests` 只是简单的代码

getRequestQueue().cancelAll(tag);

在此基础上扩展您的活动 `BaseActivity` 使用 `addToRequestQueue` 发出请求,当您的活动被销毁时,请求将自动取消。对fragment/dialog/whatever执行类似的操作。
如果您从其他任何不遵循生命周期的地方发出请求,请确保它不绑定到任何应用程序 `Context` 你会没事的。

相关问题