Android 的消息机制
主要是指handle的运行机制,需要配合messageQueue和Looper配合,Looper可以理解为消息循环,messageQueue理解为消息队列。队列主要是负责消息的排序和分配,循环负责不停的读取消息,没有就会进入等待状态,需要ThreadLocal来处理数据,它可以在不同线程中互补干扰的存储并提供数据。次线程里面默认是没有Looper的,主线程是默认创建有的。
10.1 Android的消息机制
UI验证是否是主线程由ViewRootImpl的checkThread方法来完成的,判断当前刷新UI的线程是否是主线程,不是就会抛出异常。
次线程需要手动创建Looper,handler显示send方法将一个runnable投递到内部的Looper中去处理,这个消息会调用messageQueue的enqucueMessage方法放入消息队列,然后Looper发现这个消息,处理消息,然后调用handler的handlemessage方法会调用,这个时候就会切换到handler所在的线程执行。
10.2 Android的消息机制分析
接下来主要是看源码相关,主要需要理解原理,而不是死记硬背。
10.2.1 ThreadLocal的工作原理
ThreadLocal十一个线程内部的数据存储类,通过它可以在指定的线程存储数据,只有在指定的线程中可以获取到存储的数据。
ThreadLocal另一个使用场景就是复杂逻辑下的对象传递,比如监听器的传递。
接下来是案例解析,不同线程访问同一ThreadLocal对象,但是却可以从里面读取到不同数值,这就是因为ThreadLocal会根据各自线程中取出一个数值,然后根据索引去查找对应的value值。
ThreadLocal主要是get和set方法,首先是set方法,主要是Thread类内部有一个成员专门存储ThreadLocal数据,因此获取当前线程的ThreadLocal数据就很简单,如果当前Localvalues的值为空,那么需要对其精细初始化,初始化后ThreadLocal的值进行存储。
其次是get方法,和设置类似,同样是取出当前线程的Localvalues对象,如果这个对象是空,就返回默认值,
10.2.2 消息队列的工作原理、
messageQueue主要包含两个操作,插入和读取,队列操作,但是它的实现并不是用队列,虽然功能是类似。messageQueue实际是通过一个单链表的数据结构来维护消息队列,链表在插入和删除上比较有优势。
插入方法是enqueueMessage的作用是插入一条消息,next方法是从消息队列里面读取一条消息并从消息队列中移除。enqueueMessage就是单链表的插入,没太多关注,next需要留意,next是一个无线循环的方法,如果消息没有来到,next方法会一直阻塞这样。留一下为何一直阻塞也不会报异常,可以理解为线程里面的等待,不是睡眠,有消息来才会唤醒。
10.2.3 Looper的工作原理
Looper的构造方法,可以直接调用Looper.prepare()方法就可以为当前线程生产一个Looper,接着Looper.loop()来开启循环。
Looper有两种方法退出,一个是quit直接退出,一个是quitSafely安全退出,会等待已有消息全部处理结束在退出。如果子线程中手动创建了Looper,那么退出的时候不续约建议终止Looper,不然子线程它会一直处于等待状态。
Looper的loop方法是一个是循环,除了前面说的两种方法退出,否则它会无线循环下去。
10.2.4 handler的工作原理
handler的工作主要是包括消息的发送和接收过程,消息可以通过post和send一系列方法,最终都是调用send的方法来实现的。
handler发送消息仅仅是向消息队列中插入一条消息,然后messageQueue的next()方法就会给Looper,Looper处理后交给handler来处理,也就是dispatchMessage方法会调用。
handler处理流程
1.首先检查callback是否为null,不为空就调用它。
2.否就是实现了子类,调用handleMessage(msg)方法。
handler默认构造handler()会调用当前线程的Looper,如果当前线程没有Looper,也会抛出异常。
10.3 主线程的消息循环
Android的主线程就是ActivityThread,主线程入口方法为main,然后通过Looper.prepareMainLooper()来创建主线程的Looper和MessageQueue,并通过Looper.loop()。
ActivityThread还需要一个Handler就是ActivityThread.H,它内部定义了一组消息,主要包含四大组件的启动和停止等过程。
ActivityThread通过ApplicationThread和AMS进行IPC通讯,AMS完成请求后回调ActivityThread中的binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中去执行,也就是切换到主线程里面去执行。