Android Weak Handler:可以避免内存泄漏的Handler库

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

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

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

可能导致泄漏问题的handler一般会被提示 Lint警告:

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

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

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

从上图中我们可以看到其中一个对mainactivity的引用是来自this$0this$0是什么呢?以下是关于this$0的解释:

-------什么是this$0---------

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


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

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

尼玛,还是一样的。我们看看是谁还拉着activity不放:

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

静态的Runnable加WeakReference

既然是因为mTextView引起的,那我们把mTextView换成弱引用好了:

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

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

使用静态的内部类

对所有handler/Runnable中的变量都用弱引用。

但是这种方式代码是不是很多,而且还必须得小心翼翼。

在onDestroy中清理掉所有Messages

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

运行,旋转手机

但是如果你对代码有更高的要求,觉得这样还不方便可以使用作者提供的WeakHandler

WeakHandler

WeakHandler使用起来和handler一模一样,但是他是安全的,WeakHandler使用如下:

你只需要把以前的Handler替换成WeakHandler就行了。

WeakHandler的实现原理

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

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

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

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

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

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

时间: 2024-12-21 13:30:46

Android Weak Handler:可以避免内存泄漏的Handler库的相关文章

Handler系列之内存泄漏

本篇简单的讲一下平常使用Handler时造成内存泄漏的问题. 什么是内存泄漏?大白话讲就是分配出去的内存,回收不回来.严重会导致内存不足OOM.下面来看一下造成内存泄漏的代码: public class MemoryLeakActivity extends Activity { private MyHandler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(save

Android性能优化之避免内存泄漏的建议

在android程序开发中,内存泄漏问题是比较常见的问题,相信有过一些android编程经历的程序猿都遇到过各种各样的内存泄漏.内存泄漏是造成应用程序OOM的主要原因之一,是编程中必须避免的问题.下面小编搜罗了几个避免内存泄漏的建议,分享给大家,一起来看看吧. 1.对于生命周期比Activity长的对象,如果需要应该使用ApplicationContext : 2.在涉及到Context时先考虑ApplicationContext,当然它并不是万能的,对于有些地方则必须使用Activity的Co

安卓android WebView Memory Leak WebView内存泄漏

Android WebView Memory Leak WebView内存泄漏 在这次开发过程中,需要用到webview展示一些界面,但是加载的页面如果有很多图片就会发现内存占用暴涨,并且在退出该界面后,即使在包含该webview的Activity的destroy()方法中,使用webview.destroy();webview=null;对内存占回收用还是没有任何效果.有人说,一旦在你的xml布局中引用了webview甚至没有使用过,都会阻碍重新进入Application之后对内存的gc.包括

Android WebView Memory Leak WebView内存泄漏

在这次开发过程中,需要用到webview展示一些界面,但是加载的页面如果有很多图片就会发现内存占用暴涨,并且在退出该界面后,即使在包含该webview的Activity的destroy()方法中,使用webview.destroy();webview=null;对内存占回收用还是没有任何效果.有人说,一旦在你的xml布局中引用了webview甚至没有使用过,都会阻碍重新进入Application之后对内存的gc.包括使用MapView有时一会引发OOM,几经周折在网上看到各种解决办法,在这里跟大

android WeakReference(弱引用 防止内存泄漏)与SoftReference(软引用 实现缓存机制(cache))

在Android开发中,基本上很少有用到软引用或弱引用,这两个东东若用的很好,对自己开发的代码质量的提高有很大的帮助.若用的不好,会坑了自己.所以,在还没有真正的去了解它们之前,还是慎用比较好. 下面将通过两个Demo来结识软引用和弱引用在开发中的运用. 一. WeakReference:防止内存泄漏,要保证内存被虚拟机回收. 下面以一个时间更新的Demo来说明弱引用的运用. 1. main.xml文件代码如下: [html] view plaincopy <?xml version="1

解决android中EditText导致的内存泄漏问题

开发中用到了LeankCanary,在一个简单的页面中(例如 :仅仅 包含Edittext),也会导致内训泄漏,为此,我在网上找了大量资料,最终解决.例如一个布局:<LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:focusable="true"android:focusableInTouchMode=&qu

利用Android中DDMS-&gt;Heap工具检测内存泄漏问题

1. 启动eclipse后,切换到DDMS透视图,并确认Devices视图.Heap视图都是打开的: 2. 将手机通过USB链接至电脑,链接时需要确认手机是处于“USB调试”模式,而不是作为“Mass Storage”: 3. 链接成功后,在DDMS的Devices视图中将会显示手机设备的序列号,以及设备中正在运行的部分进程信息: 4. 点击选中想要监测的进程,比如system_process进程: 5. 点击选中Devices视图界面中最上方一排图标中的“Update Heap”图标: 6.

BaseHandler的封装, 处理handler中的内存泄漏

package de.bvb.study.common; /** * 用于规范 Message.what此属性,避免出现魔法数字 */ public final class What { public static final int ZERO = 0; public static final int ONE = 1; /** 标记异步操作返回时目标界面已经消失时的处理状态 */ public static final int ACTIVITY_GONE = -1; } package de.b

Android实战技巧之三十八:Handler使用中可能引发的内存泄漏

问题描写叙述 曾几何时,我们用原来的办法使用Handler时会有以下一段温馨的提示: This Handler class should be static or leaks might occur 以下是更具体的说明(Android Studio上的警告,不知道Eclipse上是否同样) Since this Handler is declared as an inner class, it may prevent the outer class from being garbage coll