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

android线程消息机制之Handler详解

程序员文章站 2023-11-28 21:52:46
android线程消息机制主要由handler,looper,message和messagequene四个部分组成。平常在开发中,我们常用来在子线程中通知主线程来更新,其实...

android线程消息机制主要由handler,looper,message和messagequene四个部分组成。平常在开发中,我们常用来在子线程中通知主线程来更新,其实整个安卓生命周期的驱动都是通过handler(activitythread.h)来实现的。

首先我们先介绍这四个类的作用:

handler:消息的发送者。负责将message消息发送到messagequeue中。以及通过runnable,callback或者handlemessage()来实现消息的回调处理

looper:是消息的循环处理器,它负责从messagequeue中取出message对象进行处理。(looper含有messagequeue的引用)

message:是消息载体,通过target来指向handler的引用。通过object来包含业务逻辑数据。其中messagepool为消息池,用于回收空闲的message对象的。

messagequeue:消息队列,负责维护待处理的消息对象。

android线程消息机制之Handler详解

通过上面的图,我们可以比较清楚地知道他们的作用以及关系。接下来,我们从源码角度来分析这种关系是如何建立的。

public handler(looper looper, callback callback, boolean async) {
  mlooper = looper;
  mqueue = looper.mqueue;
  mcallback = callback;
  masynchronous = async;
}

hander的其它构造方法可以自己去查看,通过这个构造方法,我们知道,handler持有messagequeue的引用。所以可以方便地将message加入到队列中去。

通过源码我们发现,sendmessage->sendmessagedelayed->sendmessageattime->enqueuemessage

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

都是通过enqueuemessage将message将加入到messagequeue中。

接下来,我们看message是如何构造的。通过message的构造方法。

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

我们看到,message是通过obtain的静态方法从消息池spool中拿到的。这样可以做到消息的复用。

public static message obtain(handler h) {
  message m = obtain();
  m.target = h;

  return m;
}

其中有一个重载方法中m.target = h;这段代码非常重要,便于后面找到消息的目标handler进行处理。

接下来,我们来看looper。我们知道looper通过过looper.loop来进入循环的,而循环是通过线程的run方法的驱动的。

首先我们知道,我们在创建handler的时候,都没有去创建looper,那么looper哪里来的呢?

public handler(callback callback, boolean async) {
    ...
    mlooper = looper.mylooper();
    if (mlooper == null) {
      throw new runtimeexception(
        "can't create handler inside thread that has not called looper.prepare()");
    }
    mqueue = mlooper.mqueue;
    mcallback = callback;
    masynchronous = async;
  }

再看看looper.mylooper()

public static @nullable looper mylooper() {
    return sthreadlocal.get();
  }

threadlocal是线程创建线程局部变量的类。表示此变量只属于当前线程。

  public t get() {
    thread t = thread.currentthread();
    threadlocalmap map = getmap(t);
    if (map != null) {
      threadlocalmap.entry e = map.getentry(this);
      if (e != null) {
        @suppresswarnings("unchecked")
        t result = (t)e.value;
        return result;
      }
    }
    return setinitialvalue();
  }

我们看到了sthreadlocal.get()的方法实际是取当前线程中的looper对象。

那么我们主线程的looper到底在哪里创建的呢?
而我们清楚地知道,如果在子线程中创建handler调用,则需要使用looper.prepare方法。

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

我们看到此方法中,如果此线程中没有looper对象,则创建一个looper对象。接下来我们在源码中看到一个熟悉的方法。

  public static void preparemainlooper() {
    prepare(false);
    synchronized (looper.class) {
      if (smainlooper != null) {
        throw new illegalstateexception("the main looper has already been prepared.");
      }
      smainlooper = mylooper();
    }
  }


此方法单独的创建了一个smainlooper用于主线程的looper。这个preparemainlooper到底在哪里调用呢?

高过引用指向发现,我们在activitythread.main()方法中发现

  public static void main(string[] args) {
    ...
    looper.preparemainlooper();

    activitythread thread = new activitythread();
    thread.attach(false);

    if (smainthreadhandler == null) {
      smainthreadhandler = thread.gethandler();
    }

    if (false) {
      looper.mylooper().setmessagelogging(new
          logprinter(log.debug, "activitythread"));
    }

    // end of event activitythreadmain.
    trace.traceend(trace.trace_tag_activity_manager);
    looper.loop();

    throw new runtimeexception("main thread loop unexpectedly exited");
  }

而activitythread.main()是程序的入口方法。这样我们就非常清楚了,主线程的looper在程序的启动过程中就已经创建并循环。

那么如果在子线程中创建looper该如何正确调用呢?

class looperthread extends thread {
   public handler mhandler;

   public void run() {
     looper.prepare();

     mhandler = new handler() {
       public void handlemessage(message msg) {
         // process incoming messages here
       }
     };

     looper.loop();
   }
 }

接下来,我们需要看下looper.loop()的执行方法

public static void loop() {
    final looper me = mylooper();//拿到当前线程的looper
    if (me == null) {
      throw new runtimeexception("no looper; looper.prepare() wasn't called on this thread.");
    }
    final messagequeue queue = me.mqueue;//拿到当前looper的消息队列

    // 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 (;;) {//死循环遍历消息体。如果为null,则休眠。
      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
      final printer logging = me.mlogging;
      if (logging != null) {
        logging.println(">>>>> dispatching to " + msg.target + " " +
            msg.callback + ": " + msg.what);
      }

      final long slowdispatchthresholdms = me.mslowdispatchthresholdms;

      final long tracetag = me.mtracetag;
      if (tracetag != 0 && trace.istagenabled(tracetag)) {
        trace.tracebegin(tracetag, msg.target.gettracename(msg));
      }
      final long start = (slowdispatchthresholdms == 0) ? 0 : systemclock.uptimemillis();
      final long end;
      try {
        msg.target.dispatchmessage(msg);//此处是真正的分发消息。此处的target即是handler对象
        end = (slowdispatchthresholdms == 0) ? 0 : systemclock.uptimemillis();
      } finally {
        if (tracetag != 0) {
          trace.traceend(tracetag);
        }
      }
      if (slowdispatchthresholdms > 0) {
        final long time = end - start;
        if (time > slowdispatchthresholdms) {
          slog.w(tag, "dispatch took " + time + "ms on "
              + thread.currentthread().getname() + ", h=" +
              msg.target + " cb=" + msg.callback + " msg=" + msg.what);
        }
      }

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

最后我们看下dispatchmessage的处理方法。

  public void dispatchmessage(message msg) {
    if (msg.callback != null) {
      handlecallback(msg);
    } else {
      if (mcallback != null) {
        if (mcallback.handlemessage(msg)) {
          return;
        }
      }
      handlemessage(msg);
    }
  }

我们看到,dispatchmessage是优化处理msg.callback,然后就是实现的callback接口,最后才是handlemessage方法。

重点说明:

1、handler在实例化的时候,持有looper的引用。是通过threadlocal与handler进行关联的。

2、message在实例化的过程中,通过target 持有handler的引用。

3、通常一个线程对应一个looper.一个looper可以属于多个handler。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。