阅读时间:8 分钟编程
坐稳了没?要开车了哦安全
写在前边服务器
今天分享的内容是深刻剖析 Android 的消息机制,有些人问了,一些功能会用不就好了吗?为何还要分析底层源码呢?今天小鹿告诉你的是不少开源的项目都已经不须要咱们造轮子了,重复造轮子是多么愚蠢的一件事。可是,Android 的底层源码和一些功能的实现让咱们学习到底层的模式和逻辑实现。数据结构
学编程什么最重要,固然是逻辑思惟了,即便你什么功能都能实现,逻辑思惟能力差照样啥都干不了。你的思惟逻辑能力差,在技术路线上已经决定了你的高度。多线程
Android 的消息机制并发
Android 的消息机制主要是指 Handlerr 的运行须要底层的 MessageQueue 和 Looper 的支撑。ide
(1)MessageQueue 的中文翻译是消息队列。以队列的形式对外提供插入和删除工做。虽然叫作消息队列,可是内部存储结构并非真正的队列,而是以单链表的数据结构来存储消息列表。oop
(2)Looper 的中文翻译为循环,咱们叫它消息循环。因为 MessageQueue 只是一个存储单元,不会去处理消息。而 Looper 确弥补了这个功能,Looper 会以无限无限循环的形式去查找是否有新的消息,有的话就去处理消息,不然就一直等待。源码分析
学习思惟导图:post
之后文章中的思惟导图是小鹿给你们精心整理的,这样对每篇分享的文章都有一个清晰地结构,有利于复习和整理。
1、Android 消息机制概述
Android 消息机制主要是指 Handler 的运行机制以及 Handler 所附带的 MessageQueue 和 Looper 的工做过程。Handler 的主要做用就是将一个任务切换到某个指定的线程中去执行。
概述
(1)思考:为何 Android 要提供这个功能呢?
答:由于 Android 规定访问 UI 线程只能在主线程中进行的,若是在子线程中访问 UI ,那么程序就会抛出异常。
(2)源码:通过查看看源码的 checkThread()方法对更新 UI 是否在主线程中更新,进行抛出异常信息提示开发者(相信在开发中都遇到过这个种状况)。
(3)过程:因为以上限制,这就要求开发者必须在主线程中更新 UI,可是 Android 又建议不要在主线程中进行过于耗时的工做,不然会产生应用程序无响应 ANR。考虑到这种状况,当咱们在服务器拉去一些信息并显示到 UI 上时,拉去工做咱们将在子线程中进行,拉取完毕以后不能再子线程中直接更新 UI ,没有 Handler ,那咱们的确没有办法将访问 UI 的工做切换到主线程去执行。所以,系统之因此给咱们提供 Handler,主要缘由是为了解决在子线程中没法访问 UI 的矛盾。
(4)问题:
① 为何不能再子线程中更新 UI? 答 : 由于 Android 的 UI 控件不是线性安全的。若是在多线程中并发的访问可能会致使 UI 控件处于不可预期的状态。 ② 为何不对 UI 控件的访问加上锁机制呢? 答 :首先,加上锁机制会让访问 UI 变的复杂,其次锁机制会下降 UI 的访问效率,由于锁机制会阻塞某些线程的执行。
最简单最高效的就是采用单线程模型来处理 UI 操做,只需经过 Handlerr 切换一下 UI 访问的执行线程便可。
Handler 的工做原理
Handler 建立时就会采用当前的 Looper 来构建内部的消息循环系统,若是当前没有 Looper ,那么就会报错。
怎么解决上述问题?两个方法:
① 为当前线程建立 Looper 便可。
② 在 Looper 的线程中建立 Handler 也能够。
工做原理
(1)Handler 建立过程: Handler 被建立以后,内部的 MessageQueue 和 Looper 就与 Handler 一块儿工做协同工做了, 而后经过 Handler 的 post 方法将一个 Runnable 投递给 Handler 内部的 Looper 去处理;也能够经过 Handler 的 send 方法发送一个消息,也是经过 Looper 去处理的,其实 Post 方法最终也是经过 send 方法来完成的..
(2)send 方法的工做过程:当 Handler 的 send 方法被调用时,它会调用 MessageQueue 的 enqueueMessage 方法将这个消息放到消息队列中,而后 Looper 发现新消息,就会处理这个消息,最终消息的 Runnable 或者 Handler 的 handlerMessage 方法就会被调用。
2、 Android 的消息机制分析
消息队列的工做原理
消息队列在 Android 主要是指 MessageQueue ,MessageQueue 主要包括两个操做:插入和删除。消息队列的内部实现并非队列,实际上经过一条单链表的数据结构来维护消息队列,单链表在插入删除上颇有优点。
① 插入(enqueueMessage):往消息队列中插入一条消息。(源码实现就是单链表的插入)
② 删除(next):从消息队列中取出一条消息并将其从消息队列中移除。(next 是一个无限循环的方法,消息队列没有信息就处于阻塞状态,有新消息到来就执行单链表的删除)
Lopper 的工做原理
Looper 在 Android 消息机制中扮演着消息循环的角色,做用:不停地从 MessageQueue 中查看是否有新的消息,若是有消息就会马上处理,若是没有消息就会处于阻塞状态。
(1) Looper 的构造方法
① 建立一个 MessageQueue 消息队列。
② 将当前线程的对象保存起来。
(2)如何为一个线程建立 Looper
(Handle 的工做须要 Looper,没有 Looper 就会报错)
① 经过 Looper.prepare() 方法为线程建立一个 Looper 。 ② 经过 Looper.loop() 方法来开启消息循环。
(3)建立线程的另外一种方法
① 主线程 Looper 的获取。 Looper 这个方法主要给线程也就是 ActivityThread 建立 Looper 使用的,本质也是经过 prepare 来实现的,因为主线程的 Looper 比较特殊,因此 Looper 提供了一个 getMainLopper 的方法获取主线程的 Looper。 ② Looper 的退出。****Looper 提供了两个方法:quit 方法和 quitSafely 方法。
二者区别:quite 直接退出 Looper。
而 quitSafely 只是设定一个退出标记,先把消息队列中的消息处理完以后再退出
(4)Looper.loop() 方法实现原理
loop 是一个死循环,惟一能跳出循环的方法就是 MessageQueue 的 next 方法返回了 null。当 Looper 的 quit 方法被调用时,MessageQueue 的 quit 方法或者 quitSafely 方法就会通知消息队列退出,当消息队列被标记为退出状态时,next 就会返回一个 null。Looper 是必须退出的,不然 loop 会永远循环下去。
loop 方法会调用 MessageQueue 的 next 方法获取消息,若是 MessageQueue 没有消息,next 就会处于阻塞状态,loop 方法也会处于阻塞状态。
详解 Handler 的工做原理
Handler 的主要工做就是发送和接收消息。消息的发送能够经过 post 一系列方法以及 send 的一系列方法来实现,post 的一系列方法最终都是经过 send 一系列方法来实现的。
代码实现:
1public class HandlerActivity extends Activity { 2 3 @Override 4 protected void onCreate(@Nullable Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.activity_main); 7 8 //开启线程 9 handler(); 10 } 11 //主线程 12 Handler handler = new Handler(){ 13 14 @Override 15 public void handleMessage(Message msg) { 16 super.handleMessage(msg); 17 switch (msg.what) { 18 case 1: 19 // 获取Message里面的复杂数据 20 Bundle date = new Bundle(); 21 date = msg.getData(); 22 String name = date.getString("name"); 23 int age = date.getInt("age"); 24 String sex = date.getString("sex"); 25 //这里是主线程,可进行对UI的更新 26 textView.setText(name) 27 } 28 } 29 }; 30 31 //子线程 32 public void handler(){ 33 new Thread(new Runnable() { 34 @Override 35 public void run() { 36 Message message = new Message(); 37 message.what = 1; 38 39 // Message对象保存的数据是Bundle类型的 40 Bundle data = new Bundle(); 41 data.putString("name", "李文志"); 42 data.putInt("age", 18); 43 data.putString("sex", "男"); 44 // 把数据保存到Message对象中 45 message.setData(data); 46 // 使用Handler对象发送消息 47 handler.sendMessage(message); 48 } 49 }).start(); 50 } 51}
发送消息
经过对源码分析,Handler 发送消息的过程仅仅是向消息队列中插入一条信息,MessageQueue 的 next 方法就会返回这条信息给 Looper ,Looper 接收到消息以后就当即处理,由 Looper 交给 Handler 去处理消息,Handler 的 dispatchMessage 方法就会被调用,这时候 Handler 就进入了消息处理阶段。
消息处理
深刻 dispatchMessage 的源代码进行分析,Handler 处理消息以下:
① 首先检查 Message 的 callback 是否为 null, 不为 null 就经过 handlerCallback 来处理消息。(Message的 callback 是一个 Runnable d 对象,实际上就是 post 方法所递的 Runnable 参数)
② 其次检查 mCallback 是否为 null,不为 null 就调用 mCallback 的 handlerMessage 方法来处理消息。Callback 是个接口。
③ 咱们经过 Callback 能够采用以下的方式来建立 Handle 对象。
1Handler handler = new Handler(callback);
这样建立的意义就是建立一个实例可是并不须要派生 Handler 的子类。
④ 可是,在咱们的平常开发中,常常派生一个 Handler 的子类并重写其 handleMessage 方法来处理具体的消息,若是不想建立派生子类,就能够经过 Callback 来实现。
主线程的消息循环
Android 的主线程就是 ActivityThread,主线程的入口方法为 main ,在 main 方法中系统会经过 Looper.prepareMainLooper();来建立主线程的 Looper 以及 MessageQueue ,并经过 Looper.loop() 来开启主线程的消息循环。
主线程的消息循环开始了之后,ActivityThread 还须要一个 Handler 来和消息队列进行交互,这个 Handler 就是 ActivityThread.H 。ActivityThread 经过 ApplicationThread 和 AMS 进行进程间通讯,AMS 以进程间通讯的方式完成 ActvityThread 的请求后会回调 ApplicationThread 中的 Binder 方法,而后 ApplicationThread 向 H 发送消息,H 收到消息会将 ApplicationThread 中的逻辑切换到 ActivityThread 中去执行,即切换到主线程中去执行,这个过程就是主线程的消息循环模型。