Android Weak Handler:能够避免内存泄漏的Handler库

 

这是一个针对技术开发者的一个应用,你能够在掘金上获取最新最优质的技术干货,不只仅是Android知识、前端、后端以致于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过!前端

android使用java做为其开发环境。java的跨平台和垃圾回收机制已经帮助咱们解决了底层的一些问题。可是尽管有了垃圾回收机制,在开发android的时候仍然时不时的遇到out of memory的问题,这个时候咱们不由要问,垃圾回收机器去哪儿了?java

咱们主要讲的是handler引发的泄漏,并给出三种解决办法,其中最后一种方法就是咱们想介绍的WeakHandler 库。android

可能致使泄漏问题的handler通常会被提示 Lint警告:git

This Handler class should be static or leaks might occur 意思:class使用静态声明否者可能出现内存泄露。

 

这是一个基本的activity。在handler的post方法中咱们加入了一个匿名的runnable,同时我将其执行延迟了整整80秒。咱们运行这个程序,而且旋转几回手机,而后分析内存。github

如今内存中有7个activity了,这太不靠谱了,因此咱们来研究下为何GC没有清理它。(上图中我查询内存中activity列表时用的是oql(对象查询语言),简单强大的工具,ps 怎么用的,谁能告诉我?)swift

 

从上图中咱们能够看到其中一个对mainactivity的引用是来自this$0this$0是什么呢?如下是关于this$0的解释:后端

-------什么是this$0---------安全

非static的inner class里面都会有一个this$0的字段保存它的父对象。在Java中,非静态(匿名)内部类会默认隐性引用外部类对象。而静态内部类不会引用外部类对象。一个编译后的inner class 极可能是这样的:bash

1
2
3
4
5
6
7
8
9
class parent$inner
{
synthetic parent this $0;
parent$inner(parent this $0)
{
this . this $0 = this $0;
this $0.foo();
}
}

-------什么是this$0结束---------工具

在咱们的代码中,匿名的runnable是一个非静态的内部类,所以他会使用this$0来保存MainActivity,而后runnable会继续被它的callback引用,而callback又接着被接下来一连串的message引用,这样主线程的引用就太他妈多了。 当Activity finish后,延时消息会继续存在主线程消息队列中80秒,而后处理消息,所以handler在继续存在于内存中,而handler引用了Activity,在咱们旋转手机的时候,Activity 不停的重建和finish,致使多个activity的引用出现。

一旦将Runnable或者是Message 发送进handler,将保存一连串的引用了主线程(这里是MainActivity吧)的Message命令,直到message执行完。若是发送Runnable设置了延迟时间,那么至少在这段延迟时间内内存泄漏是确定的,若是是直接发送,在Message比较大的状况下,也是有可能发生暂时的泄漏的。

 

解决办法一:使用Static

再次执行,同时旋转手机,分析内存以下:

Analyse static runnable HPROF

尼玛,仍是同样的。咱们看看是谁还拉着activity不放:

Analyse static runnable HPROF

 

在最底下咱们发现activity继续被DoneRunnable里面mTextView中的mContext引用着。看来在这种状况下,看来仅仅使用static并无解决问题啊。还须要作点工做才行。

 

静态的Runnable加WeakReference

既然是由于mTextView引发的,那咱们把mTextView换成弱引用好了:

Static runnable with weak reference

须要注意的,既然mTextView是弱引用,因此随时均可能为null,所以须要在使用前判断是否为空。好了继续看看内存的状况:

Analyse static runnable with weak reference HPROF

all right,我想咱们已经完美的解决问题了。总结一下咱们作了哪些工做:

使用静态的内部类

对全部handler/Runnable中的变量都用弱引用。

可是这种方式代码是否是不少,并且还必须得当心翼翼。

 

在onDestroy中清理掉全部Messages

Handler有个很方便的方法:removeCallbacksAndMessages,当参数为null的时候,能够清除掉全部跟次handler相关的Runnable和Message,咱们在onDestroy中调用次方法也就不会发生内存泄漏了。

Remove callbacks code

运行,旋转手机

Analise remove callbacks HPROF

 

可是若是你对代码有更高的要求,以为这样还不方即可以使用做者提供的WeakHandler

 

WeakHandler

WeakHandler使用起来和handler如出一辙,可是他是安全的,WeakHandler使用以下:

WeakHandler code

你只须要把之前的Handler替换成WeakHandler就好了。

 

WeakHandler的实现原理

WeakHandler的思想是将Handler和Runnable作一次封装,咱们使用的是封装后的WeakHandler,但其实真正起到handler做用的是封装的内部,而封装的内部对handler和runnable都是用的弱引用。

WeakHandler diagram

第一幅图是普通handler的引用关系图

第二幅图是使用WeakHandler的引用关系图

其实原文有对WeakHandler更多的解释,可是表述起来也挺复杂的。

原文地址:https://techblog.badoo.com/blog/2014/10/09/calabash-android-query/

github项目地址:https://github.com/badoo/android-weak-handler

相关文章
相关标签/搜索