Handler可能引起的内存泄露及解决方案-android
来源:互联网 发布:网络连接小图标不见了 编辑:程序博客网 时间:2024/05/18 20:47
当对象不会被GC回收,从而导致memory leak。导致内存泄露的两种用法分别是隐式引用(implicit reference) 和 显式引用(explicit reference)。解决隐式引用的方法比较简单,只要使用内部非静态类(non-static inner class)或者 top-level class(在一个独立的java文件中定义的变量)就可以将隐式变为显式,从而避免内存泄露。
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// do something.
}
- `Android`程序第一次创建的时候,默认会创建一个`Looper`对象,`Looper`去处理`Message Queue`中的每个`Message`,主线程的`Looper`存在整个应用程序的生命周期.
- `Hanlder`在主线程创建时会关联到`Looper`的`Message Queue`,`Message`添加到消息队列中的时候`Message(排队的Message)`会持有当前`Handler`引用,当`Looper`处理到当前消息的时候,会调用`Handler#handleMessage(Message)`.就是说在`Looper`处理这个`Message`之前,会有一条链`MessageQueue -> Message -> Handler -> Activity`,由于它的引用导致你的`Activity`被持有引用而无法被回收`
- **在java中,no-static的内部类会隐式的持有当前类的一个引用。static的内部类则没有。
>具体分析:
public class SampleActivity extends Activity {
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// do something
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 发送一个10分钟后执行的一个消息
mHandler.postDelayed(new Runnable() {
@Override
public void run() { }
}, 600000);
// 结束当前的Activity
finish();
}
在`finish()`的时候,该`Message`还没有被处理,`Message`持有`Handler`,`Handler`持有`Activity`,这样会导致该`Activity`不会被回收,就发生了内存泄露.
> 解决方法
- 通过程序逻辑来进行保护。
- 如果`Handler`中执行的是耗时的操作,在关闭`Activity`的时候停掉你的后台线程。线程停掉了,就相当于切断了`Handler`和外部连接的线,`Activity`自然会在合适的时候被回收。
- 如果`Handler`是被`delay`的`Message`持有了引用,那么在`Activity`的`onDestroy()`方法要调用`Handler`的`remove*`方法,把消息对象从消息队列移除就行了,取消掉该Handler对象的Message和Runnable。
- 关于`Handler.remove*`方法
- `removeCallbacks(Runnable r)` ——清除r匹配上的Message。
- `removeCallbacks(Runnable r, Object token)` ——清除r匹配且匹配token(Message.obj)的Message,token为空时,只匹配r。
- `removeCallbacksAndMessages(Object token)` ——清除token匹配上的Message。
- `removeMessages(int what)` ——按what来匹配
- `removeMessages(int what, Object object)` ——按what来匹配 ,我们更多需要的是清除以该`Handler`为`target`的所有`Message(Callback)`就调用如下方法即可 `handler.removeCallbacksAndMessages(null)`;
- 将`Handler`声明为静态类。静态类不持有外部类的对象,所以你的`Activity`可以随意被回收。但是不持有`Activity`的引用,
如何去操作`Activity`中的一些对象? 这里要用到弱引用
public class MyActivity extends Activity {
private MyHandler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new MyHandler(this);
}
@Override
protected void onDestroy() {
// Remove all Runnable and Message.
mHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
static class MyHandler extends Handler {
// WeakReference to the outer class's instance.
private WeakReference<MyActivity> mOuter;
public MyHandler(MyActivity activity) {
mOuter = new WeakReference<MyActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MyActivity outer = mOuter.get();
if (outer != null) {
// Do something with outer as your wish.
}
}
}
}
> Handler 内部类持有 外部类Activity的引用,如果Activity退出而Handler还有延迟处理的消息没有处理完,会导致Activity不能回收,反复如此会导致内存泄露。
解决方案一: onDestroy时清除消息,mHandler.removeCallbacksAndMessages(null); // 参数为null时会清除所有消息。
解决方案二:声明Handler为static并持有Activity的弱引用。
如果继续使用非静态内部类,那么就要在onPause的时候手动结束那些挂起的任务(pending task)。
> 问题:当我们这样创建`Handler`的时候`Android Lint`会提示我们这样一个`warning: In Android, Handler classes should be static or leaks might occur.`。Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// do something.
}
}
>分析泄露的原因:- `Android`程序第一次创建的时候,默认会创建一个`Looper`对象,`Looper`去处理`Message Queue`中的每个`Message`,主线程的`Looper`存在整个应用程序的生命周期.
- `Hanlder`在主线程创建时会关联到`Looper`的`Message Queue`,`Message`添加到消息队列中的时候`Message(排队的Message)`会持有当前`Handler`引用,当`Looper`处理到当前消息的时候,会调用`Handler#handleMessage(Message)`.就是说在`Looper`处理这个`Message`之前,会有一条链`MessageQueue -> Message -> Handler -> Activity`,由于它的引用导致你的`Activity`被持有引用而无法被回收`
- **在java中,no-static的内部类会隐式的持有当前类的一个引用。static的内部类则没有。
>具体分析:
public class SampleActivity extends Activity {
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// do something
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 发送一个10分钟后执行的一个消息
mHandler.postDelayed(new Runnable() {
@Override
public void run() { }
}, 600000);
// 结束当前的Activity
finish();
}
在`finish()`的时候,该`Message`还没有被处理,`Message`持有`Handler`,`Handler`持有`Activity`,这样会导致该`Activity`不会被回收,就发生了内存泄露.
> 解决方法
- 通过程序逻辑来进行保护。
- 如果`Handler`中执行的是耗时的操作,在关闭`Activity`的时候停掉你的后台线程。线程停掉了,就相当于切断了`Handler`和外部连接的线,`Activity`自然会在合适的时候被回收。
- 如果`Handler`是被`delay`的`Message`持有了引用,那么在`Activity`的`onDestroy()`方法要调用`Handler`的`remove*`方法,把消息对象从消息队列移除就行了,取消掉该Handler对象的Message和Runnable。
- 关于`Handler.remove*`方法
- `removeCallbacks(Runnable r)` ——清除r匹配上的Message。
- `removeCallbacks(Runnable r, Object token)` ——清除r匹配且匹配token(Message.obj)的Message,token为空时,只匹配r。
- `removeCallbacksAndMessages(Object token)` ——清除token匹配上的Message。
- `removeMessages(int what)` ——按what来匹配
- `removeMessages(int what, Object object)` ——按what来匹配 ,我们更多需要的是清除以该`Handler`为`target`的所有`Message(Callback)`就调用如下方法即可 `handler.removeCallbacksAndMessages(null)`;
- 将`Handler`声明为静态类。静态类不持有外部类的对象,所以你的`Activity`可以随意被回收。但是不持有`Activity`的引用,
如何去操作`Activity`中的一些对象? 这里要用到弱引用
public class MyActivity extends Activity {
private MyHandler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new MyHandler(this);
}
@Override
protected void onDestroy() {
// Remove all Runnable and Message.
mHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
static class MyHandler extends Handler {
// WeakReference to the outer class's instance.
private WeakReference<MyActivity> mOuter;
public MyHandler(MyActivity activity) {
mOuter = new WeakReference<MyActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MyActivity outer = mOuter.get();
if (outer != null) {
// Do something with outer as your wish.
}
}
}
}
> Handler 内部类持有 外部类Activity的引用,如果Activity退出而Handler还有延迟处理的消息没有处理完,会导致Activity不能回收,反复如此会导致内存泄露。
解决方案一: onDestroy时清除消息,mHandler.removeCallbacksAndMessages(null); // 参数为null时会清除所有消息。
解决方案二:声明Handler为static并持有Activity的弱引用。
0 0
- Handler可能引起的内存泄露及解决方案-android
- Android中Handler可能引起内存泄露
- Android 中Handler可能引起的内存泄露
- Android必知必会-Handler可能引起的内存泄露
- 【android】Handler引起的内存泄露及解决办法
- Android -- Handler引起的内存泄露及解决办法
- Handler引起的内存泄露及解决办法
- Android中Handler可能引起内存泄露示例
- Android 中 Handler 引起的内存泄露
- Android 中 Handler 引起的内存泄露
- Android中Handler引起的内存泄露
- Android中Handler引起的内存泄露
- Android中Handler引起的内存泄露
- Android中Handler引起的内存泄露
- Android中Handler引起的内存泄露
- Android中Handler引起的内存泄露
- Android中Handler引起的内存泄露
- Android中Handler引起的内存泄露
- HTML中引入CSS样式有几种形式?
- 自定义UIButton一般方法
- 搜狐网站打不开了!!提示502 Bad Gateway Fss错误信息。
- Gson解析复杂的json数据
- Bootstrap 折叠
- Handler可能引起的内存泄露及解决方案-android
- 17. Letter Combinations of a Phone Number
- [Sencha ExtJS & Touch] 什么是 callParent 和 callSuper ?
- HTML与XHTML的区别?
- ContentProvider组件详解
- 设置tableView 的header和footer失去粘性以及底部出现空白的情况
- leetcode-1 TwoSum
- pod install 与 pod update的区别
- CSS笔试题