handler机制的源码分析和理解
这里写自定义目录标题
- 学习handler机制
-
- 1、创建线程消息队列
- **2、线程消息的循环过程**
- **3、线程的消息发送**
- **4、线程消息处理过程**
学习handler机制 首先举例handler的简单使用:
线程1
Runnable runnable1 = new Runnable() {
@Override
public void run() {
Looper.prepare();
//创建Looper、MessageQueue实例化对象
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("Data", "handleMessage: " + msg.obj.toString());
}
};
Looper.loop();
// 进入loop循环
}
};
线程2
Runnable runnable2 = new Runnable() {
@Override
public void run() {
Message message = handler.obtainMessage();
message.obj = "你好啊,线程一";
handler.sendMessage(message);
}
线程二中使用的 handler 是线程一中创建的 handler
线程一中使用的looper方法
Looper.prepare(); 将当前线程初始化为 消息线程
Looper.loop(); 在此线程中运行 消息队列
######################################################################################
在学习handler机制中我们必须了解其中主要的四个类的作用
1 、Looper 类是用来创建消息队列的。
2 、MessageQueue 类是用来描述消息队列的。
3、Message 类是用来描述发送的消息。
4、Handler 类是用来发送和接受消息。
1、创建线程消息队列 android中应用线程的消息队列MessageQueue是由Looper类调用prepareMainLooper() 或 prepare() 来创建。这两者之间的差别在于prepareMainLooper应用于主线程创建消息队列, prepare() 应用于子线程创建消息队列。
1.1 创建Looper 对象,然后在Looper对象的构造函数中创建MessageQueue的对象。
frameworks/base/core/java/android/os/Looper.java
public final class Looper {
.......
static final ThreadLocal sThreadLocal = new ThreadLocal();
// 用来保存Looper的实列化对象。
final MessageQueue mQueue;
//描述消息队列
private static Looper sMainLooper;
// 主线程的Looper 对象
.......
private Looper(boolean quitAllowed) {// 参数判断是否允许推出,主线程不允许退出,子线程允许退出。
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//子线程调用创建MessagerQueue: prepare() -> prepare(boolean quitAllowed) -> Looper(boolean quitAllowed)
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {//从类似hashmap的sThreadLocal中获得Looper的实列化对象
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
//如果之前没有创建过,就创建一个新的Looper对象并set进去。
}// 主线程调用创建MessagerQueue:prepareMainLooper() ->prepare(boolean quitAllowed) -> Looper(boolean quitAllowed) -> myLooper()
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
}
1.2 引入MessageQueue,然后在MessageQueue的对象中记录C++层的NativeMessageQueue对象的地址。
frameworks/base/core/java/android/os/MessageQueue.java
// mPtr 用来记录C++层NativeMessageQueue对象的地址。
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
// 创建C++层NativeMessageQueue对象
}
1.3 返回NativeMessageQueue对象的地址
frameworks/base/core/jni/android_os_MessageQueue.cpp
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return 0;
}nativeMessageQueue->incStrong(env);
return reinterpret_cast(nativeMessageQueue);
}
1.4 在NativeMessageQueue的构造函数中实列化Native Looper
frameworks/base/core/jni/android_os_MessageQueue.cpp
// getForThread() 用来判断是否已经创建过一个native 的 looper。 setForThread() 将new的Looper对象和当前进程绑定
NativeMessageQueue::NativeMessageQueue() :
mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
2、线程消息的循环过程 创建了Looper、MessageQueue之后,就开始进入Loop循环。
2.1 调用loop方法
frameworks/base/core/java/android/os/Looper.java
// 在loop()中我们首先会get到当前的looper的实例化对象, 之后再找到这个looper对应的messageQueue对象。调用next()进入messageQueue类
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper;
Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
...........
for (;
;
) {
Message msg = queue.next();
// might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
.........
}
2.2 进入MessageQueue 类
frameworks/base/core/java/android/os/MessageQueue.java
// 调用 nativePollOnce()不断的检查当前线程的消息队列中是否有新的消息需要处理。
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}int pendingIdleHandlerCount = -1;
// -1 only during first iteration
int nextPollTimeoutMillis = 0;
// 进入睡眠的等待时间。=0 ,即使没有消息进入消息队列,也不能进入睡眠。= -1 当前没有新的消息,线程就需要无限的处于睡眠等待状态。 > 0 当前线程在没有新的消息的情况下,进入睡眠状态等待的时间。
for (;
;
) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}nativePollOnce(ptr, nextPollTimeoutMillis);
..........
}
...........
}
**2.3 从next() -> nativePollOnce()
frameworks/base/core/jni/android_os_MessageQueue.cpp
**
其实在这里直接就是从nativePollOnce() -> pollOnce()
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
而在 pollOnce()又会调到 native looper的 pollOnce
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
mPollEnv = env;
mPollObj = pollObj;
mLooper->pollOnce(timeoutMillis);
mPollObj = NULL;
mPollEnv = NULL;
if (mExceptionObj) {
env->Throw(mExceptionObj);
env->DeleteLocalRef(mExceptionObj);
mExceptionObj = NULL;
}
}
2.4 从nativeMessageQueue::pollOnce -> Looper::pollOnce()
system/core/libutils/Looper.cpp
这里由于Looper::pollOnce()的代码理解难度有点大,我们这就顺带提一下它的作用有兴趣的可以查看文章 https://www.jianshu.com/p/4fac27284475
Looper::pollOnce() 的作用就是睡眠与唤醒的线程的作用。
3、线程的消息发送 3.1 Handler主要就是用来向一个线程的消息队列发送消息
frameworks/base/core/java/android/os/Handler.java
public Handler(Callback callback, boolean async) {
..........
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
mCallback = callback;
.........
}
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public void handlerMessage(Message msg) {
}
这里我们可以看到一个Handler类中有Looper 、MessageQueue成员变量。Handler 对象使用成员函数sendMessage() 向成员变量mQueue 发送消息。而成员函数handlerMessage()用来接收处理消息,他是与mLooper所关联的线程中调用的。
3.2 我们先从sendMessage() 发送一个消息开始
frameworks/base/core/java/android/os/Handler.java
从sendMessage()最后会调到sendMessageAtTime() 然后又到MesssageQueue的enqueueMessage()
这里的参数 msg 描述的是即将发送的消息,uptimeMillis则是用来描述发送的消息需要处理的时间。
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
// 将当前正在处理的一个Handler 对象。赋值给target
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
3.3 在MessageQueue中equeueMessage会对要发送的消息msg进行处理,会根据这个消息需要处理的等待时间将msg插入到合适的位置。这里不是直接的放入到messageQueue 中而是插入到Message的next指针后面
boolean enqueueMessage(Message msg, long when) {
.......
msg.markInUse();
msg.when = when;
//msg中记录等待的处理时间
Message p = mMessages;
//当前的消息
boolean needWake;
// 是否需要唤醒线程处理消息
if (p == null || when == 0 || when < p.when) { // 这里就是根据等待时间进行插入
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
//如果新进来的消息插入到消息队列的头部,那就唤醒线程进行消息处理
} else {
// Inserted within the middle of the queue.Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;
;
) {// 如果插入不是队列的头部那就继续睡眠等待
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p;
// invariant: p == prev.next
prev.next = msg;
}// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
// 唤醒目标线程
}
}
return true;
}
// 调到native 从 nativeWake()-> wake()
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr);
nativeMessageQueue->wake();
}
**3.4 最后从NativeMessageQueue又会调到Looper的wake()
system/core/libutils/Looper.cpp
**
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ wake", this);
#endifuint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
// 这里会通过管道文件描述符mWakeEventFd,向管道写一个新的数据,线程就被唤醒了。
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s",
mWakeEventFd, strerror(errno));
}
}
}
至此一个消息如何发送,如何插入到消息队列,之后唤醒线程就结束了,后面再继续分析如果接收处理一个消息。
4、线程消息处理过程 **4.1 **
持续更新。。。。。。
推荐阅读
- Laravel|Laravel 框架中使用 MongoDB 数据库的操作
- 如何优雅的修改node_modules中的依赖库
- Vue调用接口的方式有哪些()
- LR.Net解放程序员双手的代码生成器
- 如虎添翼!高德地图+Serverless 护航你的假日出行
- 62. 不同路径
- 透过PageHelper看Mybatis插件机制
- Vue中的ESLint配置方式
- 解决mybatis中resultType取出数据顺序不一致的问题
- C++算法设计之马踏棋盘的实现