Handler defines and functions

Handler is a set of message passing mechanism of AndorID. It is used for cross-thread communication. It is mainly used for interaction between worker threads and main threads. UI operations on AndorID need to be performed on the main thread, and are usually performed on other child threads. The result of a time-consuming operation can be used to communicate across threads when the UI line needs to communicate first

Handler Usage Flowchart

The principle diagram of the Handler

A few key classes:

  • Message: data unit,MessageQueueOne by one.
  • Looper:MessageQueuewithHandlerCommunication middleman. Two functions: continuous cycle fromMessageQueueRemove theMessageThat will beMessageSend to the correspondingHandler.
  • MessageQueue: Data structure (fifO) storageMessage
  • Handler: common middleman between threads,MessageThe logical processor of information willMessageSent to theMessageQueueTo deal withLooperSent overMessage

Based on using

Public class MainActivity extends appActivity {private static class MyHander extends Handler{private final WeakReference<MainActivity> mActivity ; public MyHander(MainActivity activity){ mActivity = new WeakReference<MainActivity>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg);if(null ! = mActivity.get()) { switch (msg.what){caseMactivity.get ().tonotify ();break;
                        default:
                            break;
                }
           }
        }
    }
    MyHander myHander;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); MyHander = new myHander (this); Button button = findViewById(R.id.btn); button.setOnClickListener(new View.OnClickListener() {@override public void onClick(View v) {myhander.obtainMessage (); message.what = 1; message.obj = getString(R.string.text); myHander.sendMessageDelayed(message,5000); }}); } public voidtoNotify() {... Logical operation}}Copy the code

Key Code 1: MyHanlder inherits Handler key code 2: Create a myHandler object and pass MainActivity into myHandler. MyHandler weakly references MainActivity, so myHandler # handleMessage() requires if (null! = mActivity. The get () do the null object determine key code 3: build a Message that can be obtained from the buffer pool, may also directly bring a new Message, and send the myHander. SendMessageDelayed (5000) the Message,

If you want to write MyHander as an anonymous inner class in MainActivity, you’re risking a memory leak. Because the anonymous inner class refers to the outer class, the outer class is hijacked, which can lead to a memory leak. This prevents the handler from hijacking a reference to the external MainActivity class

Handler sends data in two different forms

  1. sendxxx()The method of

    Take a look at the differences between several methods of source code:

 public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
  public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }
 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }
 public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }
    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);
    }
Copy the code

SendMessageAtTime (Message MSG, long uptimeMillis) is called at the end of each method. Note the difference between sendMessageAtTime(Message MSG, Long uptimeMillis) and sendMessageDelayed(Message MSG, Long delayMillis). One is the current moment, one is the current moment +delayMillis

2. Postxxx () method

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    public final boolean postAtFrontOfQueue(Runnable r)
    {
        return sendMessageAtFrontOfQueue(getPostMessage(r));
    }
   public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
    public final boolean postDelayed(Runnable r, Object token, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r, token), delayMillis);
    }

    public final boolean postAtTime(Runnable r, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    }
    public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
    }
Copy the code

Instead of using the sendxxx method, look at getPostMessage()

Here’s a pit to remember to look at: Handler.post(Runnable) is basically generating a Message with what = 0. If you call handler. post(Runnable) and then send any Message with what = 0, the original Message will be removed. So see a face meng force specific wait code parsing to see www.cnblogs.com/coding-way/…

The source code parsing

Start with the main thread ~ ####ActivityThread

public final class ActivityThread extends ClientTransactionHandler {
  final H mH = new H();
  final Handler getHandler() {
        return mH;
    }
  class H extends Handler {
  ......
  public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case BIND_APPLICATION:
                     ......
                    break;
                }

               case EXIT_APPLICATION:
                    ......
                    break;
          
         }
   }
   public static void main(String[] args) {
   
        Process.setArgV0("<pre-initialized>"); . // 1 looper.prepareMainLooper (); . ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); // Key code 2if(sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); }... // 3 looper.loop (); }Copy the code

PrepareMainLooper () key code 2: The mH object implements the handleMessage(Message MSG) method. Looper.loop() starts the loop

Let’s take a look at key code 1 and look at the Looper class and the object’s calling method ()

Looper (partial source code)

public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class
    final MessageQueue mQueue;
    final Thread mThread;
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if(sMainLooper ! = null) { throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    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 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; .for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return; }... try { msg.target.dispatchMessage(msg); }... }}}Copy the code
  1. Looper.prepareMainLooper(): Related call flow for this methodprepare(false)->sThreadLocal.set(new Looper(quitAllowed));->myLooper()->sThreadLocal.get()So here we have onelooperAnd set tosThreadLocalIn, the time to get fromsThreadLocalTo obtain. And inprepare(false)If the method already exists, it cannot be called againOnly one thread can existLooperAnd aLooperYou can only have onemQueueOn the other hand, indicateLooperwithMessageQueueIt’s a one-to-one relationship
  2. Looper.loop(): The related call flow of this methodme->me.mQueue– > (for (;;) -> queue.next()->msg.target.dispatchMessage(msg)) Start the endless cycle of rotation trainingMessageQueue.msg.targetIn fact, the return isHandler, the use ofHandlerSending data (about ThreadLocal, more on that later)

Now let’s look at the Handler method that sends the data dispatchMessage

Handler (partial source code)

public class Handler {
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    public interface Callback {
        public boolean handleMessage(Message msg);
    }
    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 boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }
  private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

    private static Message getPostMessage(Runnable r, Object token) {
        Message m = Message.obtain();
        m.obj = token;
        m.callback = r;
        returnm; }}Copy the code

Here you can see there are three different calls to dispatchMessage(Message MSG)

  1. handleCallback(msg): This is processingHandler.postxxx(Runnable r,xx)The sent information is processed and eventually returned to usertherunMethod inside do logic processing
  2. handleMessage(msg)withmCallback.handleMessage(msg): are used for processingHandler.sendxxx()The message sent, the difference is, instantiationHandlerStudent: Incoming or notmCallbackObject, if anymCallback.handleMessageDo logical processing, if not inhandleMessageLogical processing

Take a look at some of the properties of the Message class

Message (partial source)

public final class Message implements Parcelable {
  public int what;
  public int arg1;
  public Object obj;
  long when;
  Bundle data;
  Handler target;
  Runnable callback;
  Message next;
}
Copy the code

Message owns Handler objects, so messages sent from different Handler objects pass themselves in.

# # #

Handler passes itself to Messag and sends it to MessageQueue. Looper starts the rotation and keeps rotating MessageQueue messages, takes out the Message and uses Handler objects to call back its own methods to perform logical operations. Looper: Is stored in a ThreadLocal variable on the first instantiation, and is returned if there is none, so there is only one Looper per thread. 5. MessageQueue: is created in the constructor of Looper, and as a member variable, a thread has one and only MessageQueue Handler: Multiple threads can be created, there is no limit to how many threads can be created, and they hold handlers inside messages, so different messages can be logically manipulated by their own hijacked handalers

Handler A variety of interview questions

(You can refer to the netizen’s article)blog.csdn.net/feather_wch…