欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2022-04-13 22:52:29
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.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数据结构,链表。

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