Handle & Inner Classes 如何避免内存泄漏
来源:互联网 发布:mac 双系统丢失 编辑:程序博客网 时间:2024/06/05 09:24
查看下面一段代码
public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } };}
上面一段代码看起来很正常,但这段代码确实能造成大量的内存泄漏。并且,Android Lint(Android studio 编译器的提示) 将会给你下面的警告:
In Android, Handler classes should be static or leaks might occur.
但泄漏到底在哪里,何时发生? 我们就可以用我们所知道的来确定问题的根源:
1.Android 应用程序首次启动时,framework将会为application’s main thread 创建一个looper对象。looper实现了一个简单的message队列,循环的处理message对象。所有的主要application framework事件(例如 activity生命周期方法的调用, button的点击事件, 等等) 都包含在Message对象中,message 被添加到looper的message队列中并且逐个处理。
2.当一个handler在main thread中实例化,它将会和looper’s 消息队列关联。当handler发送一个message到消息队列中,该message对象将会持有handler的引用. 所以,当looper处理该消息的时候,framework 可以调用handler#handler(message)方法
3.在Java中,非静态内部和匿名类保留对其外部类的隐含引用。但是,静态内部类将不会。
那么内存泄漏究竟在哪里呢?这很微妙,我们以下面的代码为例:
public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mLeakyHandler.postDelayed(new Runnable() { @Override public void run() { /* ... */ } }, 1000 * 60 * 10); // Go back to the previous Activity. finish(); }}
当这个activity被销毁,延迟消息在被处理之前会继续在主线程的队列中存活10分钟。消息对象将会持有handler引用,而且handler也持有一个隐含的引用外部类(在这个例子中是SampleActivity)。这个引用直到消息被处理之前将一直保留。注意,在匿名 Runnable 类中的15行也是如此。非静态的匿名类实例持有一个他们的外部类的隐含引用,所以,context将会泄漏。
要解决这个问题,需要将继承handler的子类创建成一个新的文件, 或者使用静态内部类来代替。静态内部类不会持有他们的外部类的隐含引用,所以,activity将不会泄漏。如果你需要在handler内部调用外部activity的方法,可以在handler持有一个WeakReference 的activity,那么你讲不会意外地泄漏context。为了修复当我们实例化一个匿名Runnable 类时发生的内存泄漏,我们使变量成为该类的一个静态字段(由于匿名类的静态实例不包含对外部类的隐含引用):
public class SampleActivity extends Activity { /** * Instances of static inner classes do not hold an implicit * reference to their outer class. */ private static class MyHandler extends Handler { private final WeakReference<SampleActivity> mActivity; public MyHandler(SampleActivity activity) { mActivity = new WeakReference<SampleActivity>(activity); } @Override public void handleMessage(Message msg) { SampleActivity activity = mActivity.get(); if (activity != null) { // ... } } } private final MyHandler mHandler = new MyHandler(this); /** * Instances of anonymous classes do not hold an implicit * reference to their outer class when they are "static". */ private static final Runnable sRunnable = new Runnable() { @Override public void run() { /* ... */ } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mHandler.postDelayed(sRunnable, 1000 * 60 * 10); // Go back to the pevious Activity. finish(); }}
静态类和非静态类的区别是微妙的,但是,这是每一个android开发人员需要知道的。
最关键的是什么?如果一个内部类能够存活的比activity的生命周期还长,应该避免在activity使用非静态内部类。因此,宁可选择静态内部类并在里面持有一个弱引用的activity。
原文链接:http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html
- Handle & Inner Classes 如何避免内存泄漏
- 如何避免内存泄漏
- 如何避免内存泄漏
- 如何避免内存泄漏
- 如何避免内存泄漏?
- 如何避免Android内存泄漏
- 如何避免Android内存泄漏
- .如何避免Android内存泄漏
- 如何避免Android内存泄漏
- 什么是内存泄漏 ,如何避免?
- .NET如何避免内存泄漏
- C++如何避免内存泄漏
- Context泄漏:Handlers & Inner Classes
- handle内存泄漏问题
- 什么是JavaScript内存泄漏?如何避免内存泄漏发生?
- Qt如何尽量避免内存泄漏
- 如何避免Android内存泄漏之Context
- 如何避免内存泄漏(转载)
- Memcached和Memcache安装(64位win7)
- strtotime('yesterday')与strtotime('-1 day')获取的时间戳
- 数据处理阶段(一)
- 【QT】Item中添加控件
- Getting unknown property: app\models\CategorySearch::content
- Handle & Inner Classes 如何避免内存泄漏
- Oracle数据库的start with ... connect by
- Codevs 1421:秋静叶&秋穣子——题解
- 关于安装完Myeclipse之后的一系列配置操作
- Android7.0中文文档(API) -- ActionMenuView.OnMenuItemClickListener
- 进程遍历
- liunx下cpu占用率高如何定位代码问题
- dflist0614
- 虚拟机无法联网