使用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");
}
}
}
}
GC依赖于许多正在发生的事情。这种情况的一个可能原因是,当你在"冷启动"后执行第一个请求时,你的应用程序必须初始化各种自定义对象、片段、活动、视图缓存等,因此在增加堆并进行GC之前需要内存。
然而,我建议的解决方案是更改您的体系结构。
1) 你似乎保留了上下文参考,但从未使用过。把放下
2) 你有Volley回调,它委托给你的自定义回调,你无论如何都需要传递,为什么不简单地使用一组回调,传递给相应的请求呢。
3) 你可以WeekRef你的自定义回调,但你不能没有它们。Week Referencing并不是内存泄漏的最终解决方案。你必须弄清楚为什么裁判在你不需要的时候还在那里。
所以,如果泄漏问题发生在JsonCallback、StringCallback和ErrorCallback实现中,请尝试解决这个问题,而不是延长链并在最后切割它。
感谢djodjo的回答,帮助我达成了解决方案
-
始终使用
addToRequestQueue(request, TAG)
。这里的TAG
位是当他们的活动/片段/视图或任何东西被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
进行请求,当您的活动被销毁时,请求将自动取消。对片段/对话框/其他任何内容执行类似的操作。
如果您从其他任何不遵循生命周期的地方发出请求,请确保它没有绑定到任何Context
,这样您就可以了。