在最近使用okhttp3的过程中,使用LeakCanary检查发现引起了memory leak,排查后发现泄露发生在okhttp3.Callback中,顺便学习了非静态内部类/匿名类引起的内存泄漏问题,现摘录如下。
在JAVA中,非静态内部类/匿名类会隐式的持有外部类的引用,如果是外部类是Activity,在退出Activity后,系统不能回收Activity的资源,
导致内存泄漏。
解决这一问题,只需要将非静态内部类/匿名类改为静态的,静态的内部类/匿名类不会持有外部类的应用,这样系统就可以正常回收外部类的资源了。
“`
private static class UserBehaviorCallback implements okhttp3.Callback{
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
}
OkHttpClient client = OkHttpUtils.getInstance().getOkHttpClient();
//192.168.192.102 --> 192.168.13.7
String json = new Gson().toJson(params);
RequestBody body = RequestBody.create(JSON, json);
okhttp3.Request request = new okhttp3.Request.Builder()
.url("")
.post(body)
.build();
client.newCall(request).enqueue(new UserBehaviorCallback());
在Android中,长时间运行的任务和Acyivity生命周期进行协调会有点困难,如果你不加以小心的话会导致内存泄漏。关于如何处理这个棘手的问题,下面有几个基本的技巧供参考
1、使用静态内部类/匿名类,不要使用非静态内部类/匿名类.非静态内部类/匿名类会隐式的持有外部类的引用,外部类就有可能发生泄漏。而静态内部类/匿名类不会隐式的持有外部类引用,外部类会以正常的方式回收,如果你想在静态内部类/匿名类中使用外部类的属性或方法时,可以显示的持有一个弱引用。
2、不要以为Java永远会帮你清理回收正在运行的threads.在上面的代码中,我们很容易误以为当Activity结束销毁时会帮我们把正在运行的thread也结束回收掉,但事情永远不是这样的!Java threads会一直存在,只有当线程运行完成或被杀死掉,线程才会被回收。所以我们应该养成为thread设置退出逻辑条件的习惯。
3、适当的考虑下是否应该使用线程.Android应用框架设计了许多的类来简化执行后台任务,我们可以使用与Activity生命周期相关联的Loaders来执行简短的后台查询任务。如果一个线程不依赖与Activity,我们还可以使用Service来执行后台任务,然后用BroadcastReceiver来向Activity报告结果。另外需要注意的是本文讨论的thread同样使用于AsyncTasks,AsyncTask同样也是由线程来实现,只不过使用了Java5.0新增并发包中的功能,但同时需要注意的是根据官方文档所说,AsyncTask适用于执行一些简短的后台任务