第十章、Android的消息机制

来源:互联网 发布:表白的html源码 编辑:程序博客网 时间:2024/05/19 14:18

第十章、Android的消息机制

  1. Handler是Android消息机制的上层接口,使得我们在开发过程中只需要和Handler交互即可。
  2. Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层MessageQueue和Looper的支撑。
  3. MessageQueue的内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息的列表。
  4. Looper会以无限循环的形式去查找是否有新的消息,如果有的话就去处理消息,否则一直等待。
  5. Looper中有一个特殊的概念,ThreadLocal,它的作用是可以在每个线程中存储数据。通过ThreadLocal可以获得每个线程的Looper,需要注意的是,线程是默认没有Looper的,如果需要使用Handler就必须为线程创建Looper。
  6. ActivityThread被创建时就会初始化Looper,这也是主线程中默认可以使用Handler的原因。

1. Android消息机制的概述

  1. Handler的主要作用是将一个任务切换到某个指定线程中去执行。
  2. Android的UI控件不是线程安全的,如果在多线程中并发访问可能 会导致UI处于不可预期的状态。
  3. 为什么不对UI控件加上锁机制?

    1. 加上锁机制会让UI访问的逻辑变得复杂
    2. 锁机制会降低UI访问的效率。
  4. Handler创建时会采用当前线程的Looper来构建内部的消息循环系统,如果当前线程没有Looper那么就会报错。解决方法就是在当前线程中创建Looper,或者在一个有Looper的线程中创建Handler。

  5. 调用Handler的post或者send方法时,Handler就会调用MessageQueue的enqueueMessage就会将这个消息放入消息队列中,然后Looper发现新消息到来时,就会处理这个消息。最终消息中的Runnable或者Handler的handleMessage方法就会被调用。
  6. Looper是运行在创建Handler所在的线程中的。
  7. Handler工作过程:

Handler工作过程

2.Android消息机制分析

1. ThreadLocal工作原理
  1. ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其它线程来说则无法获取到数据。
  2. 当数据是以线程为作用域并且不同线程具有不同的数据副本的时候,可以考虑使用ThreadLocal.
  3. ThreadLocal 另一个使用场景就是复杂逻辑下的对象传递,比如监听器的传递。
  4. 不通过线程中访问的是同一个ThreadLocal对象,但是它们通过ThreadLocal获取到的值确实一样的。之所以会这样,是因为不同线程访问同一个ThreadLocal的get方法,ThreadLoca内部会从各自的线程中取出一个数组,然后再从数据中根据当前ThreadLocal索引去查找对应的value值。所以不同线程中的数组是不同的。
  5. 从ThreadLocal的set和get方法可以看出,它们所操作的对象都是当前线程的localValues对象的table数组,因此在不同线程中访问同一个ThreadLocal的set和get方法,它们对ThreadLocal所做的读、写操作权限仅限于各自线程的内部,这就是为什么在多个线程中可以互不干扰地存储和修改数据。
2.消息队列的工作原理
  1. 消息队列在Android中指的是MessageQueue,MessageQueue主要包含两个操作:插入和读取。读取操作本身会伴随着删除操作。插入和删除分别对应enqueue和next。MessageQueue本身是通过一个单链表的数据结构来维护消息列表。
  2. enqueueMessage的作用是往消息队列中插入一条消息;next的作用是从消息队列中取出一条消息并将消息从队列中移除。
  3. next方法是一个无线循环的方法,如果消息队列中没有消息,那么next方法会一直堵塞在这里。当有新消息时,next方法会返回这条消息并将其从单链表中移除。
3.Looper的工作原理
  1. Looper在Android的消息机制中扮演者消息循环的角色,它会不停地从MessageQueue中查看是否有新的消息,如果有新的消息就会立刻处理,否则就一直阻塞在那里。
  2. 通过Looper.prepare()可以为当前线程创建一个Looper,通过Looper.loop()开启消息循环。
  3. prepareMainLooper方法,可以给ActivityThread创建Looper使用。
  4. 通过getMainLooper可以在任何地方获取到主线程的Looper。
  5. Looper可以退出,quit和quitSafely用来退出一个Looper。两者之间的区别:
    1. quit会直接退出Looper。
    2. quitSafely只是设定了一个退出标记,然后把消息队列中的已有消息处理完毕后才会安全退出。

  6. Looper退出后,通过Handler发送的消息会失败,这个时候Handler的send方法会返回false。如果Looper退出后,这个线程会立即终止。如果没有通过quit退出消息循环,那么这个子线程会一直处于等待状态。

4.Handler的工作原理
  1. Handler的主要工作包含消息的发送和接收过程,消息的发送可以通过post的一系列方法以及send的一些列方法来实现,post的一系列方法最终通过send的一系列方法来实现。
  2. Handler发送消息的过程仅仅是向消息队列中插入一条消息,MessageQueue的next方法就会返回这条消息给Looper,Looper收到消息后就开始处理了,最终消息由Looper交由Handler处理,即Handler的dispatchMessage就会被调用。

3. 主线程消息循环

  1. Android的主线程就是ActivityThread,主线程的入口方法为main,在main方法中系统会通过Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue,并通过Looper.loop()来开启主线程的消息循环。
  2. 主线程的消息循环开始后,ActivityThread还需要一个Handler来和消息队列进行交互,这个Handler就是Activity.H,它内部定义了一组消息类型,主要包含了四大组件的启动和停止等过程。
  3. AcitivityThread通过ApplicationThread和AMS进行进程间通信,AMS以进程间通的方式完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到ActivityThread中执行,切换到主线程中去执行。这个过程就是主线程的消息循环模型。
0 0