返回

深入剖析 Handler(二):API 及内存泄漏问题

Android

相关API
    如果我们想创建工作线程时,其实并不需要在新建线程的时候创建handler,因为系统会为每个线程创建一个looper,只要获取当前线程的looper就能操作handler了。常用的api函数有:
    MessageQueue.next():取出消息队列中的消息。
    Message.obtain(Handler,Runnable):获得一个runnable消息。
    Message.obtain(Handler,int,Object):获得一个int值消息。
    Message.obtain(Handler,int,int,Object):获得一个带两个int值的消息。
    Message.sendToTarget():把消息发送到目标handler。
    Message.getTarget():获得消息的目标handler。
    Handler.dispatchMessage(Message):处理消息。
    Handler.sendMessage(Message):发送消息。
    Handler.sendMessageDelayed(Message,long):延迟发送消息。
    Handler.removeMessages(int):移除消息。
    Handler.postDelayed(Runnable,long):延迟执行runnable。

内存泄漏

    虽然handler是一个很强大的工具,但是handler与activity有很大的关系,需要在activity创建和销毁的时候进行一些处理,否则会产生内存泄漏。这是因为handler的内部类callback会持有外部类activity的引用,即使activity已经被销毁了,但是callback对象中依然持有这个activity的引用,这就导致了内存泄漏。
    解决这个问题有两种方法,一种是把activity的引用设置为weakReference,这样当activity被销毁后,弱引用自动会变成null,从而解决内存泄漏。
    另一种方法是使用静态内部类,这种方法同样不会持有外部类的引用,同样可以解决内存泄漏的问题。但是对于一些大型的项目,每个activity都有多个handler的话,势必要创建很多静态内部类,这样会非常混乱。
    因此,最佳的方法还是使用弱引用,但是需要注意弱引用在GC的时候会变成null,可能造成一些错误,所以需要自己做一些判断。

相关 API

1. MessageQueue.next()

  • 作用:取出消息队列中的消息。

2. Message.obtain(Handler, Runnable)

  • 作用:获得一个 Runnable 消息。

3. Message.obtain(Handler, int, Object)

  • 作用:获得一个 int 值消息。

4. Message.obtain(Handler, int, int, Object)

  • 作用:获得一个带两个 int 值的消息。

5. Message.sendToTarget()

  • 作用:把消息发送到目标 Handler。

6. Message.getTarget()

  • 作用:获得消息的目标 Handler。

7. Handler.dispatchMessage(Message)

  • 作用:处理消息。

8. Handler.sendMessage(Message)

  • 作用:发送消息。

9. Handler.sendMessageDelayed(Message, long)

  • 作用:延迟发送消息。

10. Handler.removeMessages(int)

  • 作用:移除消息。

11. Handler.postDelayed(Runnable, long)

  • 作用:延迟执行 Runnable。

内存泄漏

1. 问题

  • Handler 与 Activity 有很大的关系,需要在 Activity 创建和销毁的时候进行一些处理,否则会产生内存泄漏。这是因为 Handler 的内部类 Callback 会持有外部类 Activity 的引用,即使 Activity 已经被销毁了,但是 Callback 对象中依然持有这个 Activity 的引用,这就导致了内存泄漏。

2. 解决方法

  • 解决这个问题有两种方法:
    • 使用弱引用(WeakReference)
    • 使用静态内部类(Static Inner Class)