Source code analysis and understanding handler mechanism

Learning handler mechanism

First, a simple example using the handler:
Thread 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循环
        }
    };

Thread 2

Runnable runnable2 = new Runnable() {
        @Override
        public void run() {
            Message message = handler.obtainMessage();
            message.obj = "你好啊,线程一";
            handler.sendMessage(message);
        }

Handler thread in two thread handler is used to create a
looper thread a method used
Looper.prepare (); the current thread is initialized to a message thread
Looper.loop (); Message Queuing In this thread

######################################################################################

In the study handler mechanism, we must understand the role of four major classes of which
1, Looper class is used to create a message queue .
2, the MessageQueue class is used to describe the message queue .
. 3, the Message type is used to describe the message sent .
. 4, Handler class is used to send and receive messages .

1, create a message queue thread

android application thread's message queue MessageQueue calling prepareMainLooper () or prepare () class to create a Looper. The difference between these two is applied to the primary thread creates prepareMainLooper message queue, prepare () is applied to the sub-thread creation message queue.
1.1 Looper create an object, and then create an object in the constructor Looper MessageQueue object.
frameworks / base / core / java / android / os / Looper.java

public final class Looper { 
.......
	static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); // 用来保存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 introduced, the address of the C ++ objects NativeMessageQueue layer then recorded MessageQueue object.
frameworks / base / core / java / android / os / MessageQueue.java

	// mPtr 用来记录C++层NativeMessageQueue对象的地址。
   MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();  // 创建C++层NativeMessageQueue对象
    }

1.3 NativeMessageQueue return address of an object
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<jlong>(nativeMessageQueue);
}

1.4 in the constructor of a solid column of NativeMessageQueue Looper Native
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, cycle message thread

After creating a Looper, MessageQueue, we began to enter the Loop cycle.
2.1 call the loop method
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 from the Next () -> nativePollOnce ()
frameworks / Base / Core / JNI / android_os_MessageQueue.cpp
**
In fact, here is directly from nativePollOnce () -> pollOnce ()

static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
        jlong ptr, jint timeoutMillis) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}

In pollOnce () will be transferred pollOnce native looper's

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;
    }
}

:: pollOnce 2.4 from nativeMessageQueue -> Looper :: pollOnce ()
System / Core / libutils / Looper.cpp

here due Looper :: pollOnce () code to understand the difficulty a bit big, so we are Incidentally it is the role of interest You can view the article https://www.jianshu.com/p/4fac27284475
Looper :: pollOnce () role is the role of sleep and wake up the thread.

3, threaded messaging

3.1 Handler is mainly used to send a message to the thread's message queue
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) {
    }

Here we can see a Handler class has Looper, MessageQueue member variables. Handler object using the member functions sendMessage () sends a message to the member variable mQueue. The member function handlerMessage () for receiving and processing the news, he was associated with the thread mLooper called in.

3.2 We send a message to start sendMessage () start
frameworks / Base / Core / the Java / Android / os / Handler.java

() will eventually be transferred from sendMessageAtTime sendMessage () and then to MesssageQueue of enqueueMessage ()

Here is described msg parameter message to be sent, uptimeMillis is used to describe the time message transmitted to process.

   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 msg message is processed in the MessageQueue equeueMessage will be transmitted, the waiting time will be based on this message needs to be processed into an appropriate position msg. This is not directly put into the messageQueue but inserted behind the next pointer Message

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<NativeMessageQueue*>(ptr);
    nativeMessageQueue->wake();
}

3.4 ** Looper last turn transferred from the wake NativeMessageQueue ()
System / Core / libutils / Looper.cpp
**

void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ wake", this);
#endif

    uint64_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));
        }
    }
}

At this point how to send a message, how to insert into the message queue, and then wake up the thread is over, back then continue to analyze if a message is received treatment.

4, the message processing thread

** 4.1 **
continuously updated. . . . . .

Published 14 original articles · won praise 4 · Views 3513

Guess you like

Origin blog.csdn.net/lisiwei1994/article/details/102505034