Android Handler异步消息处理机制总结

Android Handler异步消息处理机制总结_第1张图片
异步消息处理机制图

1、一个线程中只能有一个Looper对象,一个MessageQueue(消息队列)对象,多个Handler对象。
2、Handler的作用发送和接收消息。
3、Hander在线程中实例化前,必须先looper.prepare()

问:分析为什么使用异步消息处理机制可以对UI进行操作?
答:因为handler的创建必须依附在线程中。假如handler创建在UI线程中,而子线程无法直接更新UI,这时通过handler的发送消息,MessageQueue对消息的入队、出队一系列操作,最后调用handler的handleMessage()方法接收消息,而此时handleMessage()运行在UI线程,所以可以对其进行UI操作。

问:handler导致内存泄漏,原因是什么,怎么解决?
答:内存泄漏:Java通过GC(垃圾回收)自动检测内存中的对象,如果GC发现一个或者一组对象为不可到达状态,则将该对象从内存中回收。也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现时回收。另外一组对象中,只包含互相的引用,而没有来自他们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这也属于不可到达状态。本该被回收的对象没被回收就是内存泄漏。

handler泄漏原因:
当使用内部类(包括匿名类)来创建handler时,Handler对象会隐式地持有一个外部类的(通常是一个Activity)引用。Handler一般伴随一个耗时的后台线程出现,这个后台新线程任务执行之后,通过消息机制通知Handler,然后Handler把消息发送到UI线程。然而,如果用户在耗时线程执行过程中关闭了Activity(正常情况下Activity不再被使用,它就有可能在GC检查时被回收掉),这时线程尚未执行完,而该线程持有Handler的引用,这个Handler又持有Activity的引用,就导致了该Activity暂时无法被回收。

handler泄漏解决办法:
方案一:
  1、通过程序逻辑来进行保护在关闭Activity的时候停掉你的后台线程。线程停掉了,相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。
  2、如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。
方案二:将Handler声明为静态类
  静态类不持有外部类的对象,所以你的Activity可以随意被回收。代码如下:

static class TestHandler extends Handler 
  { @Override public void handleMessage(Message msg) {           mImageView.setImageBitmap(mBitmap); 
  }
}

这时你会发现,由于Handler不再持有外部类对象的引用,导致程序不允许你在Handler中操作Activity中的对象了。所以你需要在Handler中增加一个对Activity的弱引用(WeakReference),如下:

static class TestHandler extends Handler {
    WeakReference mActivityReference;

    TestHandler(Activity activity) {
        mActivityReference= new WeakReference(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        final Activity activity = mActivityReference.get();
        if (activity != null) {
            mImageView.setImageBitmap(mBitmap);
        }
    }
}

你可能感兴趣的:(Android Handler异步消息处理机制总结)