安卓 Handler 消息机制(总)

注:本文参考于某公开课,如有侵权,请联系本人,会立即删除

注:仅用作自我学习记录,未有任何商业用途。

关于handler的由来

开始前的闲言碎语

        我们都知道handler是安卓的消息传递机制,使用handler可以实现多线程通信。还有常说的handler四大成员:handler、message、messageQueue、looper,及其功能:

        Message:封装需要传递的消息,可以传递数据;
        MessageQueue:消息队列,但是它的内部实现并不是用的队列,而是通过一个单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势。主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);
        Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);
        Looper:不断循环执行(Looper.loop),从MessageQueue中读取消息,按分发机制将消息分发给目标处理者。

        但是,android系统是由Java封装的,那为什么还要在Java已经实现了多线程通信的前提下,增加自己的多线程通信机制呢?

        这就要从Java的多线程通信说起。

        Java中实现多线程之间相互通信访问数据有很多方法,常见的有:

        1.通过关键字“syncheronized”给对象上锁的方法实现线程间的通信:即多个线程持有同一个对象,他们都访问同一个“共享变量”,但是同一时间只有拿到对象锁的线程,可以访问“共享变量”,其他线程只能等待对象锁被释放才有可能获得对象锁,从而去访问“共享变量”。

        2.使用Object的wait/notify机制,当object调用wait()方法后,该object所在线程进入阻塞状态,直到其他线程调用notify(法,object所在线程才被唤醒。

        这些方法都绕不开一个共同的特点:阻塞!!!

        作为鲜明的特点,我们知道:

        1. android系统是由JAVA封装的。

        2. android将app启动时运行的线程称为主线程或UI线程

        3. 耗时操作(网络请求、数据库操作等)都要放到子线程(又叫工作线程)中去,不能在UI线程(又叫主线程)中执行(防止UI线程阻塞,否则会ANR:这里的阻塞是指,UI线程长时间去执行某个耗时操作,而无法响应用户的操作,导致的ANR)。

        4. 只有UI线程可以更新UI。

        那现在就需要线程间的通信了:UI线程不能执行耗时任务,要交给子线程,子线程执行完任务后,又不能把结果直接反馈的UI上,需要先把结果给UI线程,由UI线程去更新UI。如下图:

 android中实现多线程通信的方法有:

1. view.post(Runnable runnable):通过view切换回UI线程

2. activity.runOnUiThread(Runnable runnable):通过activity对象的引用切换回UI线程

3. AsyncTask:内部封装了UI线程和工作线程的切换操作

4. Handler机制。

总结:由于android的特殊性,创建了UI线程;由于UI线程的特殊性,创建了许多工作线程和UI线程通信的方法,handler就是其中一种“android多线程通信机制”。

Handler

handler按其特点理解,提供的方法大体无非就三种作用:发送消息、处理消息、切换线程。

1.发送消息:

· boolean sendEmptyMessage(int what);

· boolean sendEmptyMessageAtTime(int what,long time);

· boolean sendEmptyMessageDelayed(int what,long delay);

· boolean sendMessage(Message msg);

· boolean sendMessageAtTime(Message msg,long time);

· boolean sendMessageDelayed(Message msg,long  delay);

2.处理消息:

void handleMessage(Message msg);

3.切换线程:

· boolean post(Runnable r)

· boolean postAtTime(Runnable r, long time)

· boolean postDelayed(Runnable r,long delay)

(注:其实这里的切换线程,只是说对应的事务操作不用回到创建handler的地方,在重写的handleMessage中处理,而是直接在runnable中重写的run方法执行而已。)

说明:

        以上方法总中参数“AtTime”和“Delayed”都是毫秒值,不同的是:前者的时间参数是指从系统开机时间算起的“time”毫秒后;而后者是从当前时间开始算起的“delay”毫秒后。

        SystemClock.updateTimeMillis()可以获取系统开机到现在的毫秒数。

        到此,handler机制的中的1/4成员handler基本介绍完了,是不是想说这些我都知道,哈哈,和你一样,我也就知道这么多。回归正题,总结一波:

1. handler的作用无非就是发送消息、切换线程、处理消息。

2. 在使用中,我们在哪个线程中创建了handler实例,哪个线程就是这个handler的“载体”、消息的接收端:在其他线程调用本线程的handler的sendMessage发送消息,那这条消息都会在本线程重写的方法handleMessage中接收到。

3. handler接受消息端是线程独立的,只有实例化本Handler的线程接受消息;但handler发送消息端多线程共享的:即拥有本Handler的引用的线程都可以作为消息的发送端,调用handler的发送消息方法来发送消息。所以,handler不是线程独立的。

所以,Handler需要一个独立存在于线程内部私有使用的类来帮助它接受消息!

对,就是Looper!由此,Looper的作用就是辅助Handler接收消息且独立于线程内部。

那么问题又来了,如果同时有多个线程通过handler的引用向该handler发送消息,那么Looper怎么同时处理这些消息呢?

于是,为了防止多线程同时发消息Looper忙不过来,又设计了一个MessageQueue类,以队列的方式保存着Looper从其他线程接收到未来得及发送给handler处理的消息,这样,Looper就可以一个个的有序的从MessageQueue中取出消息处理了。

可见,设计MessageQueue是为Looper服务的,Looper是线程独立的,那么MessageQueue也是线程独立的。

至此,handler四大成员全部亮相了。

小结:

1.Handler的引用是多线程共享的。

2.Message:提供的消息的标准化封装,视为消息的载体

3.MessageQueue:以队列的形式保存着待处理的消息

4. Looper:消息接收端,负责不断从MessageQueue中取出消息分发给handler接受消息端。

为了规范消息传递的格式定义了Message。

为了实现消息接收端值存在于线程内部私有化使用定义了Looper。

为了解决多线程同时发送数据Looper发来消息处理时会产生的问题而设计了MessageQueue。

这里关于消息接收端的理解(要区别消息的接受和处理时不同的概念):

对外:handler的实例化所在的线程即为消息的接收端;在handler内部,实际是looper接受了消息,并保存到了消息队列中,然后通过不断循环,按顺序一个个取出,交给handler去处理,即执行  void handleMessage(Message msg);  方法。

        

总结一下,四大成员的关系:

1.一个线程可以有多个Handler,而对于Handler来说,一个Handler只能实例化在某一个线程中,但其引用可以在任意多个线程(即前面说到的消息的发送端有多个,接收端只有一个)。

2. 一个线程只有一个looper,一个looper又唯一对应一个MessageQueue。

下一篇讲Message源码

  

猜你喜欢

转载自blog.csdn.net/set_one_name/article/details/125692822
今日推荐