Android -> 如何避免Handler引起内存泄露

更多内容,可访问个人博客www.liangfeizc.com

错误代码

如果在Activiy中通过内部类(Runnable)的方式定义了一个变量runnable,

final Runnable runnable = new Runnable() {
    public void run() {
        // ... do some work
    }
};
handler.postDelayed(runnable, TimeUnit.SECONDS.toMillis(10)

因为Runnable不是static类型,所以会有一个包含Activity实例的implicit reference --- Activity.this。

如果Activity在runnable变量run之前(10s内)被finish掉了但是Activity.this仍然存在,那么Activity的对象就不会被GC回收,从而导致memory leak

即使使用一个静态内部类,也不能保证万事大吉。

static class MyRunnable implements Runnable {
    private View view;
    public MyRunnable(View view) {
        this.view = view;
    }
    public void run() {
        // ... do something with the view
    }
}

假设在runnable执行之前,View被移除了,但是成员变量view还在继续引用它,仍然会导致memory leak

上面的两个例子当中,导致内存泄露的两种用法分别是隐式引用(implicit reference)显式引用(explicit reference)

解决方法

解决隐式引用的方法比较简单,只要使用内部非静态类(non-static inner class)或者 top-level class(在一个独立的java文件中定义的变量)就可以将隐式变为显式,从而避免内存泄露。

如果继续使用非静态内部类,那么就要在onPause的时候手动结束那些挂起的任务(pending task)。

关于如何结束任何,Handler可参考这篇文章中的Canceling a pending RunnableCanceling pending Messages。HandlerThread可参考这篇文章

解决第二个问题要用到WeakReference,WeakReference的用法可以google一下,简而言之就是:只要还有其他的stronger reference,WeakReference就可以继续引用。

static class MyRunnable implements Runnable {
    private WeakReference>View< view;
    public MyRunnable(View view) {
        this.view = new WeakReference>View<(view);
    }
    public void run() {
        View v = view.get();
        if (v != null) {
            // ... do something with the view
        }
    }
}

这样一来问题就解决了,美中不足的是每次使用view之前都要做空指针判断。另外一个比较高效的方法就是在onResume中为runnable的view赋值,在onPause中赋值为null。

private static class MyHandler extends Handler {
    private TextView view;
    public void attach(TextView view) {
        this.view = view;
    }
    public void detach() {
        view = null;
    }
    @Override
    public void handleMessage(Message msg) {
        // ....
    }

总结

在继承Handler或者HandlerThread的时候,

  • 尽量定义一个static类或者top-level类。
  • 如果用到了ui元素,一定要在Activity的生命周期接触之前释放掉。

参考

Asynchronous Android - Steve Liles

时间: 2024-08-02 19:17:01

Android -> 如何避免Handler引起内存泄露的相关文章

Android中使用Handler造成内存泄露的分析和解决

什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收:另外,如果一组对象中只包含互相的引用,而没有来自它们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这仍然属于不可到达,同样会被GC回收. Android中使用Handler造成内存泄露的原因 Handler mHand

Android使用Handler造成内存泄露的分析及解决方法

一.什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收:另外,如果一组对象中只包含互相的引用,而没有来自它们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这仍然属于不可到达,同样会被GC回收. Android中使用Handler造成内存泄露的原因 private Han

[转载] 从Handler.post(Runnable r) ,Handler.sendEmptyMessage()梳理Android的消息机制(以及handler的内存泄露)

Handler 每个初学Android开发的都绕不开Handler这个"坎",为什么说是个坎呢,首先这是Android架构的精髓之一,其次大部分人都是知其然却不知其所以然.今天看到Handler.post这个方法之后决定再去翻翻源代码梳理一下Handler的实现机制. 异步更新UI 先来一个必背口诀"主线程不做耗时操作,子线程不更新UI",这个规定应该是初学必知的,那要怎么来解决口诀里的问题呢,这时候Handler就出现在我们面前了(AsyncTask也行,不过本质

Android OOM(Out of memory) 内存泄露基本知识

Android OOM(Out of memory) 内存泄露基本知识 转载至:http://blog.csdn.net/emilychai2010/article/details/12710135 1. 内存泄露 2. Android里的垃圾回收 3. Heap 4. 调试 5. 常见的内存泄露 1.什么是内存泄露(memory leak)? A "memory leak" in your code is when you keep a reference to an object

Handler导致内存泄露分析

Handler mHandler = new Handler() {    @Override    public void handleMessage(Message msg) {            // do something.    }}```当我们这样创建`Handler`的时候`Android Lint`会提示我们这样一个`warning: In Android, Handler classes should be static or leaks might occur.`. 一

Activity内部Handler引起内存泄露的原因分析

有时在Activity中使用Handler时会提示一个内存泄漏的警告,代码通常如下: public class MainActivity extends Activity { private TextView tvHelloWorld; private Button btnSetText; private Handler mHandler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) {

android:布局、绘制、内存泄露、响应速度、listview和bitmap、线程优化以及一些优化的建议!

1.布局优化 首先删除布局中无用的控件和层级,其次有选择地使用性能较低的viewgroup,比如布局中既可以使用RelativeLayout和LinearLayout,那我们就采用LinearLayout,因为RelativeLayout的功能比较复杂,它的布局需要花费 风度哦的CPU实际. 布局优化的另一个手段就是采用<include>,<merge>,<viewstub>标签.<include>主要用于布局重用,<include>,<m

Android内存泄露分析和处理

什么是内存泄露 Java使用有向图机制,通过GC自动检查内存中的对象,如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收. 内存泄露的原因 1.资源对象没关闭造成的内存泄漏 资源性对象比如 (Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存.它们的缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外.如果我们仅仅是把它的引用设置为null

Android Handler内存泄露

前言 在Android开发中,使用Handler的地方很多,大致通常写法如下: private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what == 1) { mAdapter.notifyDataSetChanged(); } }};这段代码看似没什么问题,但是里面却有一个警告,警告信息如下: This Handler class should