[Android]Context泄露之谜:Handle & 内部类
来源:互联网 发布:用java编写的过关游戏 编辑:程序博客网 时间:2024/06/06 07:26
先上译文路径。
考虑下面代码:
public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } }
尽管不是太明显,这段代码可能会导致严重的内存泄露。Android Lint 会给出如下警告
In Android, Handler classes should be static or leaks might occur.
可内存泄露是如何发生的呢?定位问题需要先列出我们已知的东西:
Android
应用第一次启动时, 系统会在主线程创建Looper
对象,Looper
实现了一个简单的消息队列,循环处理Message
。所有主要的应用层事件(例如Activity
的生命周期方法回调、Button
点击事件等等)都会包含在Message
里,系统会把Message
添加到Looper
中,然后Looper
进行消息循环.。主线程的Looper
会存在整个应用的生命周期间。当主线程创建
Handler
对象,会与消息队列Looepr
绑定,被分发到消息队列的Message
会持有Handler
的引用,以便系统在Looper
处理到该Message
时能调用Handle#handlerMessage(Message)
方法。- 在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
生命周期结束后,延迟的Message
在被处理之前会继续停留在主线程中10分钟。该Message
持有该Activity
的Handler
的引用,而Handler
持有外部类(SampleActivity
)的隐式引用。该引用会继续存在直到Message
被处理。所以阻止了Activity
和Context
的回收,泄漏了所有应用的resources
。注意上述代码第15行。非静态类和匿名内部类都会持有外部类的隐式引用,导致了Context
泄漏。
为了解决这个问题,可以用新建一个Handler的静态子类。静态内部类不会持有外部类的隐式引用。因此不会导致内存泄漏。如果你需要在Handler子类中调用外部类的方法,可以让Handler
持有一个Activity
的WeakReference
。为了防止内存泄漏,我们新建一个静态的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 previous Activity. finish(); }}
静态内部类和非静态内部类的区别很微妙,但每一个Android开发者都应该注意到这个标准,避免在Activity
中使用非静态内部类,如果该类的实例会存在在Activity
的生命周期之外。必须使用静态内部类持有一个外部类的弱引用替代。
原文链接:http://www.jianshu.com/p/63aead89f3b9
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
- [Android]Context泄露之谜:Handle & 内部类
- [Android]Context泄露之谜:Handle & 内部类
- [Android]Context泄露之谜:Handle & 内部类
- Context内存泄露:Handler&内部类
- 什么导致了Context泄露:Handler&内部类
- [译]Handlers和内部类如何造成Context泄露
- 什么导致了Context泄露:Handler&内部类
- 【译】什么导致了Context泄露:Handler&内部类
- 什么导致了Context泄露:Handler&内部类
- 什么导致了Context泄露:Handler&内部类
- 什么导致了Context泄露:Handler&内部类
- android之Context内存泄露
- Android内存泄露之Context
- 避免使用非静态内部类,这会导致Context泄露
- Android:Handler,内部类导致的可能内存泄露
- Android中的内部类引起的内存泄露
- Android中的内部类引起的内存泄露
- Android 非静态内部类导致的内存泄露(非static内部类)
- ffmpeg无损合并视频的多种方法
- HashMap源码分析以及四种遍历方法
- 个人总结——一些凌乱代码的使用
- 公交时间预测线性回归模型
- Android开发屏幕适配方案
- [Android]Context泄露之谜:Handle & 内部类
- 1.Spring基本用法
- final关键字
- 字符编码的故事(ASCII ISO GBK GB2312 UTF-8)
- 【POJ 3630】Phone List(静态字典树)
- java开发定义一个好的变量名
- 前端js冷知识
- AES加解密算法详解
- 自学java(2)