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 collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.

大概意思就是:

一旦Handler被声明为内部类,那么可能导致它的外部类不可以被垃圾回收。假设Handler是在其它线程(我们通常成为worker thread)使用Looper或MessageQueue(消息队列)。而不是main线程(UI线程),那么就没有这个问题。

假设Handler使用Looper或MessageQueue在主线程(main thread),你须要对Handler的声明做例如以下改动:

声明Handler为static类。在外部类中实例化一个外部类的WeakReference(弱引用)而且在Handler初始化时传入这个对象给你的Handler;将全部引用的外部类成员使用WeakReference对象。

解决方式一

上面的描写叙述中基本上把推荐的改动方法明白表达了出来。以下的代码是我自己使用中的一个实现,请參考:

private CopyFileHandler mHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_appstart);
    mHandler = new CopyFileHandler(this);
    startCopyDBThread();
}

private void startCopyFileThread(){
    Log.d(TAG, "startCopyDBThread");
    new Thread(new Runnable() {
        @Override
        public void run() {
            //DO SOMETHING LIKE: copyDBFile();
            Message msg=mHandler.obtainMessage();
            mHandler.sendMessage(msg);
        }
    }).start();
}

private static class CopyFileHandler extends Handler {
    WeakReference<AppStartActivity> mActivity;
    public CopyFileHandler(AppStartActivity activity) {
        mActivity = new WeakReference<>(activity);
    }

    public void handleMessage(Message msg) {
        final AppStartActivity activity = mActivity.get();
       //handle you message here!
    }
}

为什么会内存泄漏

那么为什么不这样做会引发内存泄漏呢?

这与几个关键词有关:内部类、Handler的消息循环(Looper)、Java垃圾回收机制。

须要强调一下,并非每次使用Handler都会引发内存泄漏。这里面有一定的几率,须要满足特定条件才会引起泄漏。

内部类会有一个指向外部类的引用。

垃圾回收机制中约定。当内存中的一个对象的引用计数为0时。将会被回收。

Handler作为Android上的异步消息处理机制(好吧,我大多用来进行worker thread与UI线程同步),它的工作是须要Looper和MessageQueue配合的。简单的说,要维护一个循环体(Looper)处理消息队列(MessageQueue)。

每循环一次就从MessageQueue中取出一个Message。然后回调对应的消息处理函数。

假设,我是说假设,循环体中有消息未处理(Message排队中),那么Handler会一直存在。那么Handler的外部类(一般是Activity)的引用计数一直不会是0,所以那个外部类就不能被垃圾回收。

非常多人会遇到activity的onDestroy方法一直不运行就是这个原因。

还有一个解决方式的尝试

警告描写叙述中提到了Handler在worker thread中使用Looper或MessageQueue,我尝试了一下。请大家品鉴。

    private Handler testHandler;
    private Thread mThread = new Thread() {
        public void run() {
            Log.d(TAG,"mThread run");
            Looper.prepare();
            testHandler = new Handler() {
                public void handleMessage(Message msg) {
                    Log.d("TAG", "worker thread:"+Thread.currentThread().getName());
                    switch (msg.what) {
                        //handle message here
                    }
                }
            };
            Looper.loop();
        }
    };

    //start thread here
    if(Thread.State.NEW == mThread.getState()) {
        Log.d(TAG, "mThread name: " + mThread.getName());
        mThread.start();
    }

    //send message here
    testHandler.sendEmptyMessage(1);

參考:

http://stackoverflow.com/questions/11407943/this-handler-class-should-be-static-or-leaks-might-occur-incominghandler

http://m.blog.csdn.net/blog/wurensen/41907663

http://blog.csdn.net/lmj623565791/article/details/38377229

时间: 2024-10-12 16:28:01

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

Android实战技巧之三十:人脸检测-静态

最近微软的how-old.net把人脸识别技术又大大的火了一把.通过大数据和复杂的算法,能够神奇的预测出照片中人物的性别和年龄.虽然错误率也不低,但是大家都抱着玩一玩乐一乐的心态把照片传上去让机器来鉴定一下自己的颜龄. 人脸识别算法是高深复杂的,面对着计算机视觉的种种数学公式,我就已经投降了.先来简单的玩玩人脸检测吧.Android早已提供了FaceDetector类,今天就来看看如何使用这个类人脸检测吧. 流程: 1.打开文件夹选择照片 2.将照片加载到bitmap中并缩放到设置的宽高 3.用

Android实战技巧之三十二:Android Studio中的源代码管理

Android Studio最近经过了两次升级到了Android Studio 1.2.1.1, 用起来是越来越顺手了.AS中加入了主流的源码管理工具,让开发者不用离开AS就可以提交和管理代码. 下面就演示一下在AS中使用git管理代码. 选择要提交的代码 右键->commit 编写commit message 可以选择commit and push一起完成提交的动作 确认后push 查看提交历史和对比文件 总结: 玩git的都知道在命令行下有些版本历史信息的显示是不方便的,我们需要借助gitk

Android实战技巧之十八:adb取出安装在手机中的apk

场景: 朋友看见你Android手机中的游戏或应用很好玩,也想装一个此程序,但限于网络条件不能从网上下载.那么最简单的办法就是直接从你手机中将此apk扣出来给他安装上. pm命令 第一步,找到程序的包名 借助adb shell pm命令,将安装的所有应用包名列出来: $ adb shell pm list packages package:android package:cn.wps.moffice package:com.android.backupconfirm package:com.an

Android实战技巧之三十五:了解native activity

1.native activity的意义 很多人觉得Android的Fwk提供的支持足够好了,既然Google不推荐用Ndk开发为什么又放宽Ndk的限制而推出可以无Java开发Android App呢?我的理解是不同的技术实现会有其适合的场景. Ndk的适用场景官方给出三点:1.平台间的App移植 2.复用现有库 3.对软件性能要求较高的场合比如游戏等.那么native activity在十分适合游戏领域,比如cocos-2dx对其的使用. 2.初步了解native activity 借助SDK

Android实战技巧之三十六:Makefile快速入门

目标 通过一篇文章的介绍达到能够编写简单Makefile以及能够看懂普通的Makefile之目的. make简介 make是一个老牌的构建(build)工具,1970年问世以来已经度过了45年的时光而魅力不减,这在技术发展日新月异的今天是不可思议的.make在大型的软件项目中发挥着巨大作用.我是在学习Linux kernel时才第一次接触它,Android系统也是用make和python等脚本一起构建系统,所以掌握make知识是你迈进这些系统的第一道坎.你一定要给予make足够的重视,不要以为掌

Handler使用中可能引发的内存泄漏

https://my.oschina.net/rengwuxian/blog/181449 http://www.jianshu.com/p/cb9b4b71a820 http://blog.csdn.net/u014665060/article/details/55820435 http://www.cnblogs.com/baiqiantao/p/10f7070ba7800d9f81bf76002958919c.html http://blog.csdn.net/lincyang/artic

Android实战技巧之四十四:Hello,Native!

在Android上运行C程序对于做上层App的童鞋来说有些陌生,因为目前的Android应用开发怎么还是绕不过Java. 但对于底层驱动开发者,这就是家常便饭一样,因为Android是Linux分支,底层是C/C++的世界. 有时为了测试一些功能,我们也会编写直接运行在Android终端下的C程序.前提是有Android交叉编译器以及Android系统的root权限. 交叉编译工具 ndk为我们开发native程序做了很多工作,下面我们将Android交叉编译工具从ndk中分离出来. 我的系统是

Android实战技巧之四十九:Usb通信之USB Host

零 USB背景知识 USB是一种数据通信方式,也是一种数据总线,而且是最复杂的总线之一. 硬件上,它是用插头连接.一边是公头(plug),一边是母头(receptacle).例如,PC上的插座就是母头,USB设备使用公头与PC连接. 目前USB硬件接口分三种,普通PC上使用的叫Type:原来诺基亚功能机时代的接口为Mini USB:目前Android手机使用的Micro USB. Host USB是由Host端控制整个总线的数据传输的.单个USB总线上,只能有一个Host. OTG On The

【转】Android实战技巧之四十九:Usb通信之USB Host

零 USB背景知识 USB是一种数据通信方式,也是一种数据总线,而且是最复杂的总线之一. 硬件上,它是用插头连接.一边是公头(plug),一边是母头(receptacle).例如,PC上的插座就是母头,USB设备使用公头与PC连接. 目前USB硬件接口分三种,普通PC上使用的叫Type:原来诺基亚功能机时代的接口为Mini USB:目前Android手机使用的Micro USB. Host USB是由Host端控制整个总线的数据传输的.单个USB总线上,只能有一个Host. OTG On The