当前位置: 移动技术网 > IT编程>移动开发>Android > Android消息循环机制源码深入理解

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

张凯丽0929,国家图书馆少年儿童馆,品味书香 诵读经典

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.getmessage(), 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;
}

@override
public 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数据结构,链表。

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网