Android消息循环机制源码深入理解

Android消息循环机制源码深入理解,第1张

概述Android消息循环机制源码前言:搞Android的不懂Handler消息循环机制,都不好意思说自己是Android工程师。面试的时候一般也都会问这个知识点,但是我相信大多数码农肯定是没有看过相关源码的,顶多也就是网上搜搜,

AndroID消息循环机制源码

前言:

搞AndroID的不懂Handler消息循环机制,都不好意思说自己是AndroID工程师。面试的时候一般也都会问这个知识点,但是我相信大多数码农肯定是没有看过相关源码的,顶多也就是网上搜搜,看看别人的文章介绍。学姐不想把那个万能的关系图拿出来讨论。

近来找了一些关于androID线程间通信的资料,整理学习了一下,并制作了一个简单的例子。

 andriod提供了 Handler 和 Looper 来满足线程间的通信。例如一个子线程从网络上下载了一副图片,当它下载完成后会发送消息给主线程,这个消息是通过绑定在主线程的Handler来传递的。

在AndroID,这里的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper,这个事androID的新 概念。我们的主线程(UI线程)就是一个消息循环的线程。针对这种消息循环的机制,我们引入一个新的机制Handle,我们有消息循环,就要往消息循环里 面发送相应的消息,自定义消息一般都会有自己对应的处理,消息的发送和清除,消息的的处理,把这些都封装在Handle里面,注意Handle只是针对那 些有Looper的线程,不管是UI线程还是子线程,只要你有Looper,我就可以往你的消息队列里面添加东西,并做相应的处理。
但是这里还有一点,就是只要是关于UI相关的东西,就不能放在子线程中,因为子线程是不能 *** 作UI的,只能进行数据、系统等其他非UI的 *** 作。

  在AndroID,这里的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper,这个是androID的新概念。我们的主线程(UI线程)就是一个消息循环的线程。针对这种消息循环的机制,我们引入一个新的机制Handler,我们有消息循环,就要往消息循环里面发送相应的消息,自定义消息一般都会有自己对应的处理,消息的发送和清除,把这些都封装在Handler里面,注意Handler只是针对那 些有Looper的线程,不管是UI线程还是子线程,只要你有Looper,我就可以往你的消息队列里面添加东西,并做相应的处理。

但是这里还有一点,就是只要是关于UI相关的东西,就不能放在子线程中,因为子线程是不能 *** 作UI的,只能进行数据、系统等其他非UI的 *** 作。

先从我们平时的使用方法引出这个机制,再结合源码进行分析。

我们平时使用是这样的:

 //1. 主线程 Handler handler = new MyHandler(); //2. 非主线程 HandlerThread handlerThread = new HandlerThread("handlerThread"); handlerThread.start(); Handler handler = new Handler(handlerThread.getLooper()); //发送消息 handler.sendMessage(msg); //接收消息 static class MyHandler extends Handler {  //对于非主线程处理消息需要传Looper,主线程有默认的sMainLooper  public MyHandler(Looper looper) {   super(looper);  }  @OverrIDe  public voID handleMessage(Message msg) {   super.handleMessage(msg);  } }

那么为什么初始化的时候,我们执行了1或2,后面只需要sendMessage就可处理任务了呢?学姐这里以非主线程为例进行介绍,handlerThread.start()的时候,实际上创建了一个用于消息循环的Looper和消息队列MessageQueue,同时启动了消息循环,并将这个循环传给Handler,这个循环会从MessageQueue中依次取任务出来执行。用户若要执行某项任务,只需要调用handler.sendMessage即可,这里做的事情是将消息添加到MesSAEQueue中。对于主线程也类似,只是主线程sMainThread和sMainLooper不需要我们主动去创建,程序启动的时候Application就创建好了,我们只需要创建Handler即可。

我们这里提到了几个概念:

HandlerThread 支持消息循环的线程 Handler 消息处理器 Looper 消息循环对象 MessageQueue 消息队列 Message 消息体

对应关系是:一对多,即(一个)HandlerThread、Looper、MessageQueue -> (多个)Handler、Message

源码解析

1. Looper

(1)创建消息循环

prepare()用于创建Looper消息循环对象。Looper对象通过一个成员变量ThreadLocal进行保存。

(2)获取消息循环对象

myLooper()用于获取当前消息循环对象。Looper对象从成员变量ThreadLocal中获取。

(3)开始消息循环

loop()开始消息循环。循环过程如下:

每次从消息队列MessageQueue中取出一个Message

使用Message对应的Handler处理Message

已处理的Message加到本地消息池,循环复用

循环以上步骤,若没有消息表明消息队列停止,退出循环

public static voID prepare() { prepare(true);}private static voID prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) {  throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed));}public static Looper myLooper() { return sThreadLocal.get();}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; // Make sure the IDentity of this thread is that of the local process,// and keep track of what that IDentity token actually is. Binder.clearCallingIDentity(); final long IDent = Binder.clearCallingIDentity(); for (;;) {  Message msg = queue.next(); // might block  if (msg == null) {   // No message indicates that the message queue is quitting.   return;  }  // This must be in a local variable,in case a UI event sets the logger  Printer logging = me.mLogging;  if (logging != null) {   logging.println(">>>>> dispatching to " + msg.target + " " +     msg.callback + ": " + msg.what);  }  msg.target.dispatchMessage(msg);  if (logging != null) {   logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);  }  // Make sure that during the course of dispatching the  // IDentity of the thread wasn't corrupted.  final long newIDent = Binder.clearCallingIDentity();  if (IDent != newIDent) {   Log.wtf(TAG,"Thread IDentity changed from 0x"     + Long.toHexString(IDent) + " to 0x"     + Long.toHexString(newIDent) + " while dispatching to "     + msg.target.getClass().getname() + " "     + msg.callback + " what=" + msg.what);  }  msg.recycleUnchecked(); }}

2. Handler

(1)发送消息

Handler支持2种消息类型,即Runnable和Message。因此发送消息提供了post(Runnable r)和sendMessage(Message msg)两个方法。从下面源码可以看出Runnable赋值给了Message的callback,最终也是封装成Message对象对象。学姐个人认为外部调用不统一使用Message,应该是兼容Java的线程任务,学姐认为这种思想也可以借鉴到平常开发过程中。发送的消息都会入队到Messagequeue队列中。

(2)处理消息

Looper循环过程的时候,是通过dispatchMessage(Message msg)对消息进行处理。处理过程:先看是否是Runnable对象,如果是则调用handleCallback(msg)进行处理,最终调到Runnable.run()方法执行线程;如果不是Runnable对象,再看外部是否传入了Callback处理机制,若有则使用外部Callback进行处理;若既不是Runnable对象也没有外部Callback,则调用handleMessage(msg),这个也是我们开发过程中最常覆写的方法了。

(3)移除消息

removeCallbacksAndMessages(),移除消息其实也是从MessageQueue中将Message对象移除掉。

public voID handleMessage(Message msg) {}public voID dispatchMessage(Message msg) { if (msg.callback != null) {  handleCallback(msg); } else {  if (mCallback != null) {   if (mCallback.handleMessage(msg)) {    return;   }  }  handleMessage(msg); }}private static voID handleCallback(Message message) { message.callback.run();}public final Message obtainMessage(){ return Message.obtain(this);}public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r),0);}public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg,0);}private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m;}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; if (mAsynchronous) {  msg.setAsynchronous(true); } return queue.enqueueMessage(msg,uptimeMillis);}public final voID removeCallbacksAndMessages(Object token) { mQueue.removeCallbacksAndMessages(this,token);}

3. MessageQueue

(1)消息入队

消息入队方法enqueueMessage(Message msg,long when)。其处理过程如下:

待入队的Message标记为InUse,when赋值

若消息链表mMessages为空为空,或待入队Message执行时间小于mMessage链表头,则待入队Message添加到链表头

若不符合以上条件,则轮询链表,根据when从低到高的顺序,插入链表合适位置

(2)消息轮询

next()依次从MessageQueue中取出Message

(3)移除消息

removeMessages()可以移除消息,做的事情实际上就是将消息从链表移除,同时将移除的消息添加到消息池,提供循环复用。

boolean enqueueMessage(Message msg,long when) { if (msg.target == null) {  throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) {  throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) {  if (mQuitting) {   IllegalStateException e = new IllegalStateException(     msg.target + " sending message to a Handler on a dead thread");   Log.w("MessageQueue",e);   msg.recycle();   return false;  }  msg.markInUse();  msg.when = when;  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;}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; for (;;) {  if (nextPollTimeoutMillis != 0) {   Binder.flushPendingCommands();  }  nativePollOnce(ptr,nextPollTimeoutMillis);  synchronized (this) {   // Try to retrIEve the next message. Return if found.   final long Now = SystemClock.uptimeMillis();   Message prevMsg = null;   Message msg = mMessages;   if (msg != null && msg.target == null) {    // Stalled by a barrIEr. Find the next asynchronous message in the queue.    do {     prevMsg = msg;     msg = msg.next;    } while (msg != null && !msg.isAsynchronous());   }   if (msg != null) {    if (Now < msg.when) {     // Next message is not ready. Set a timeout to wake up when it is ready.     nextPollTimeoutMillis = (int) Math.min(msg.when - Now,Integer.MAX_VALUE);    } else {     // Got a message.     mBlocked = false;     if (prevMsg != null) {      prevMsg.next = msg.next;     } else {      mMessages = msg.next;     }     msg.next = null;     if (false) Log.v("MessageQueue","Returning message: " + msg);     return msg;    }   } else {    // No more messages.    nextPollTimeoutMillis = -1;   }   // Process the quit message Now that all pending messages have been handled.   if (mQuitting) {    dispose();    return null;   }   // If first time IDle,then get the number of IDlers to run.   // IDle handles only run if the queue is empty or if the first message   // in the queue (possibly a barrIEr) is due to be handled in the future.   if (pendingIDleHandlerCount < 0     && (mMessages == null || Now < mMessages.when)) {    pendingIDleHandlerCount = mIDleHandlers.size();   }   if (pendingIDleHandlerCount <= 0) {    // No IDle handlers to run. Loop and wait some more.    mBlocked = true;    continue;   }   if (mPendingIDleHandlers == null) {    mPendingIDleHandlers = new IDleHandler[Math.max(pendingIDleHandlerCount,4)];   }   mPendingIDleHandlers = mIDleHandlers.toArray(mPendingIDleHandlers);  }  // Run the IDle handlers.  // We only ever reach this code block during the first iteration.  for (int i = 0; i < pendingIDleHandlerCount; i++) {   final IDleHandler IDler = mPendingIDleHandlers[i];   mPendingIDleHandlers[i] = null; // release the reference to the handler   boolean keep = false;   try {    keep = IDler.queueIDle();   } catch (Throwable t) {    Log.wtf("MessageQueue","IDleHandler threw exception",t);   }   if (!keep) {    synchronized (this) {     mIDleHandlers.remove(IDler);    }   }  }  // reset the IDle handler count to 0 so we do not run them again.  pendingIDleHandlerCount = 0;  // While calling an IDle handler,a new message Could have been delivered  // so go back and look again for a pending message without waiting.  nextPollTimeoutMillis = 0; }}voID removeMessages(Handler h,int what,Object object) { if (h == null) {  return; } synchronized (this) {  Message p = mMessages;  // Remove all messages at front.  while (p != null && p.target == h && p.what == what    && (object == null || p.obj == object)) {   Message n = p.next;   mMessages = n;   p.recycleUnchecked();   p = n;  }  // Remove all messages after front.  while (p != null) {   Message n = p.next;   if (n != null) {    if (n.target == h && n.what == what     && (object == null || n.obj == object)) {     Message nn = n.next;     n.recycleUnchecked();     p.next = nn;     continue;    }   }   p = n;  } }}

4. Message

(1)消息创建

Message.obtain()创建消息。若消息池链表sPool不为空,则从sPool中获取第一个,flags标记为UnInUse,同时从sPool中移除,sPoolSize减1;若消息池链表sPool为空,则new Message()

(2)消息释放

recycle()将消息释放,从内部实现recycleUnchecked()可知,将flags标记为InUse,其他各种状态清零,同时将Message添加到sPool,且sPoolSize加1

/** * Return a new Message instance from the global pool. Allows us to * avoID allocating new objects in many cases. */public static Message obtain() { synchronized (sPoolSync) {  if (sPool != null) {   Message m = sPool;   sPool = m.next;   m.next = null;   m.flags = 0; // clear in-use flag   sPoolSize--;   return m;  } } return new Message();}/** * Return a Message instance to the global pool. * <p> * You MUST NOT touch the Message after calling this function because it has * effectively been freed. It is an error to recycle a message that is currently * enqueued or that is in the process of being delivered to a Handler. * </p> */public voID recycle() { if (isInUse()) {  if (gCheckRecycle) {   throw new IllegalStateException("This message cannot be recycled because it "     + "is still in use.");  }  return; } recycleUnchecked();}/** * Recycles a Message that may be in-use. * Used internally by the MessageQueue and Looper when disposing of queued Messages. */voID recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUID = -1; when = 0; target = null; callback = null; data = null; synchronized (sPoolSync) {  if (sPoolSize < MAX_POol_SIZE) {   next = sPool;   sPool = this;   sPoolSize++;  } }}

5. HandlerThread

由于Java中的Thread是没有消息循环机制的,run()方法执行完,线程则结束。HandlerThread通过使用Looper实现了消息循环,只要不主动调用HandlerThread或Looper的quit()方法,循环就是一直走下去。

public class HandlerThread extends Thread {int mPriority;int mTID = -1;Looper mLooper;public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAulT;}@OverrIDepublic voID run() { mTID = Process.myTID(); Looper.prepare(); synchronized (this) {  mLooper = Looper.myLooper();  notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTID = -1;}public Looper getLooper() { if (!isAlive()) {  return null; } // If the thread has been started,wait until the looper has been created. synchronized (this) {  while (isAlive() && mLooper == null) {   try {    wait();   } catch (InterruptedException e) {   }  } } return mLooper;}public boolean quit() { Looper looper = getLooper(); if (looper != null) {  looper.quit();  return true; } return false;}}

总结

关键类:HandlerThread、Handler、Looper、MessageQueue、Messaga MessageQueue数据结构,链表。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

总结

以上是内存溢出为你收集整理的Android消息循环机制源码深入理解全部内容,希望文章能够帮你解决Android消息循环机制源码深入理解所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1145647.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存