天天看点

handler消息机制

MessageQueue代码:http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/os/MessageQueue.java/?v=source

Handler代码:

http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/os/Handler.java/?v=source

Looper代码:

http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/os/Looper.java/?v=source

 为什么有handler,handler的主要作用是什么?

首先android UI主线程不能进行大量的耗时操作,否则会产生ANR以及不好的UI体验,因此必须通过异步的方式处理耗时的操作,避免耗时的操作阻塞UI主线程。

handler的主要作用是什么呢,主要负责多个线程之间的信息通信,比如子线程中中耗时操作返回结果需要在UI线程进行展示,这时候就需要通过handler来将消息传递到UI线程并刷新UI内容。

handler的消息机制主要牵扯三方面:

消息发送者;

消息队列;

消息处理循环操作。

handler发消息有两种方式:

send

sendEmptyMessage(int),发送一个空的消息;

sendMessage(Message),发送消息,消息中可以携带参数;

sendMessageAtTime(Message, long),未来某一时间点发送消息;

sendMessageDelayed(Message, long),延时Nms发送消息。

post

post(Runnable),提交计划任务马上执行;

postAtTime(Runnable, long),提交计划任务在未来的时间点执行;

postDelayed(Runnable, long),提交计划任务延时Nms执行。

messageQueue:消息队列,对外提供插入和删除的工作,内部存储结构为单链表结构。

messageQueue的两个主要方法:

enqueueMessage:向消息队列中插入元素;

next:从消息队列中取出元素,是个无线循环的方法,无消息,阻塞,有消息,返回消息并从消息队列中将消息移除。

looper:用来构建轮训消息队列系统。

线程默认没有looper,使用handler就必须为线程创建looper。

Looper.prepare()创建Looper;

Looper.loop()开启消息循环;

Looper.prepareMainLooper()主线程创建looper;

quit:直接退出Looper;

quitSafely:设定退出标志,已有消息处理完以后才会退出。

消息发送:post方式发送消息的方式最后调用的还是sendMessage方式:

往下走:

最后走到这里:

调用 enqueueMessage 在消息队列中插入一条消息,在 enqueueMessage总中,会把 msg.target 设置为当前的Handler 对象。

如下将消息插入消息队列中去。并且可以很明显看出消息队列是线性链表结构。

每个线程只能运行一个looper对象,创建 Looper 的时候,内部会创建一个消息队列MessageQueue;并且looper在线程里面必须先prepare(),再loop来对消息队列messageQueue来进行遍历循环操作。

循环遍历并分发消息出去msg.target.dispatchMessage(msg),切换到创建handler所使用的looper中执行,也就是说将逻辑切换到主线程去:

 额,先写到这,明天继续更新。

hander的相关问题的延伸:

handler在实际开发中常见的问题就是内存泄漏的问题了:

常见的写法:

1,在Java中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用,静态的内部类不会持有外部类的引用,通过将类声明为静态的,解决持有外部类引用的问题;

2,android主线程有looper,looper处理MessageQueue消息队列数据的进进出出,<code>Message</code>添加到消息队列中的时候<code>Message(排队的Message)</code>会持有当前<code>Handler</code>引用,处理消息,并在ui界面上进行结果展示或者toast()或者dialog对话框弹出,就会产生MessageQueue 到 Message 到 Handler 到 Activity的引用链。

为了解决静态内部类无法操作外部类的内容,将activity作为弱引用引入,这样就就可以避免引用的问题,有可以对外部类的方法进行调用。

那么如何解决呢?

 还有一种解决方式:WeakHandler

开源库地址:https://github.com/badoo/android-weak-handler

实际项目中使用:

1,引入:compile 'com.badoo.mobile:android-weak-handler:1.1',当然也可以代码引入,就一个类;

2,代码中的使用:

声明以及在主线程中接收消息,注意和我们的handler的写法的不同:

发送消息:

继续阅读