Thorough analysis of Android asynchronous message mechanism at source level (1)

Handler、Message、Loopler、MessageQueen

First, let's take a look at one of the most common uses of handler.

Handler handler =new Handler(){
    @Override
    public void handleMessage(Message msg) {
      super.handleMessage(msg);
      //这里进行一些UI操作等处理
    }

     new Thread(new Runnable() {
      @Override
      public void run() {
        Message message = Message.obtain();
        ........
        handler.sendMessage(message);
      }
    });
  };

Take a look at the source code of the constructor of handler

public Handler() {
  this(null,false);
}
//他会调用本类中的如下构造函数
public Handler(Callback callback,boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
      final Class<? extends Handler> klass = getClass();
      if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
          (klass.getModifiers() & Modifier.STATIC) == 0) {
        Log.w(TAG,"The following Handler class should be static or leaks might occur: " +
          klass.getCanonicalName());
      }
    }

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

We see that when mloop = = null, an exception "can't create handler inside thread that has not called loop. Prepare()" will be thrown, so we need to call loop. Prepare() before creating the handler instance

public static void prepare() {
    prepare(true);
}
//将looper保存到ThreadLocal中,这里可以把ThreadLocal理解为一个以当前线程为键的Map,所以一个线程中只会有一个looper
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));
}
//我们看到在new Looper(quitAllowed)中,创建了一个消息队列MessageQueen
private Looper(boolean quitAllowed) {
  mQueue = new MessageQueue(quitAllowed);
  mThread = Thread.currentThread();
}

Next, let's look at the handler. SendMessage (message) method, which literally means to send messages. Generally, the SendMessage method will eventually call the sendmessageattime (message MSG, long uptimemillis) method

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

We see that the method enqueuemessage (queue, uptimemillis) will eventually be executed

private boolean enqueueMessage(MessageQueue queue,Message msg,long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
      msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg,uptimeMillis);
  }

Finally, the method queue. Enqueuemessage (MSG, uptimemillis) in messagequeue will be called. The queue here is the message queue created in the looper constructor

//MessageQueen的enqueueMessage方法
  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(TAG,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;
  }

Although the name of messagequeen is a queue, it is essentially a one-way linked list. This structure can quickly insert and delete operations. As can be seen from the above source code, MSG is mainly inserted into the message queue in the chronological order of sending messages. Next, we need to get MSG from the message queue. At this time, you need to call the looper. Loop () method.

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 (;;) {
      //不断从消息队列中取出msg
      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交由handler处理
      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();
    }
  }

You can see that the Looper.loop () method takes the message out of the message queue by calling Message MSG = queue.next () in a dead loop. The function of the queue. Next () method is to get MSG from the message queue. The only way out of the loop is that the next method of messagequeue returns null. Now that the MSG has been removed, the next step is how to pass it to the handler, right. Therefore, there is another method MSG. Target. Dispatchmessage (MSG) in the dead loop, and MSG. Target is the handler. In the enqueuemessage () method of handler above, MSG. Target = this, which is the handler itself. Next, let's look at the dispatchmessage () method of handler

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
      handleCallback(msg);
    } else {
      if (mCallback != null) {
        if (mCallback.handleMessage(msg)) {
          return;
        }
      }
      handleMessage(msg);
    }
  }

If we use a parameterless constructor to create a handler, msg.callback and mcallback are empty, so we will call handlemessage (MSG), so the whole process of the instance at the beginning of the article will be completed, and handlemessage (MSG) will be executed in the thread where the handler instance is located.

//当我们通过这种方式创建handler时,dispatchMessage中的mCallback就不为null
 public Handler(Callback callback) {
    this(callback,false);
 }
//Callback是一个接口,里面正好也有我们需要的handleMessage(Message msg),dispatchMessage中的 if (mCallback != null) 语句内的内容,就是我们需要重写的handleMessage(Message msg)方法
 public interface Callback {
   public boolean handleMessage(Message msg);
 }

//当我们调用handler.post()方法执行异步任务时
  public final boolean post(Runnable r)
  {
    return sendMessageDelayed(getPostMessage(r),0);
  }
//getPostMessage(r)这个方法中我们看到给m.callback赋值了,就是我们传入的runnable接口
  private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
  }
//最后在handleCallback方法中我们执行了它的run方法,这也就解释了为什么在子线程中可以用handler.post(Runnable r)更新UI
  private static void handleCallback(Message message) {
    message.callback.run();
  }

summary

Sort out the whole implementation process

1. Call looper. Prepare () method, which is necessary to create handler. In the main thread, since the activitythread has created a loop through the loop. Preparemainloop() method, it is not necessary to create a loop before creating a handler in the main thread, and start the message loop of the main thread through loop. Loop().

2. By calling the handler.sendmessage (message) method, enqueuemessage (queue, uptimemillis) will eventually be executed, and enqueuemessage will call the queue.enqueuemessage (MSG, uptimemillis) of messagequeue, so that the message will be added to the message queue.

3. Call the looper. Loop() method to execute message MSG = queue. Next() in the dead loop, constantly take MSG out of the message queue, and execute MSG. Target. Dispatchmessage (MSG) at the same time to pass the message to the handler for processing. For example, handlemessage we call is one of the ways to process the message.

Flow chart of asynchronous processing mechanism

Several ways of UI operation from sub threads

Android provides several ways to access UI threads from other threads. Several useful methods are listed below:

• activity.runonuithread (runnable) • view.post (runnable) the view here is the UI control we need to change • view.postdelayed (runnable, long) • handler.post (runnable, long)

However, as operations become more complex, such code will become complex and difficult to maintain. To handle more complex interactions through a worker thread, consider using a handler in the worker thread to process messages from the UI thread. Of course, the best solution may be to extend the asynctask class, which simplifies the worker tasks required to interact with the UI.

The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>