Handler机制源码解析

来源:互联网 发布:淘宝联盟怎么得佣金 编辑:程序博客网 时间:2024/05/20 17:27

Handler提供了两种方式解决问题(在一个新线程中更新主线程中的UI控件),一种是调用sendMessage方法,一种是通过post方法。

  • sendMessage方法

    通常会重写handleMesaage方法

    在另一个线程下调用sendMessage方法(或者其他sendMessageXXX系列方法)

    在handleMessage方法中处理信息

  • post方法

    调用post系列的方法,传入参数是Runnable的实现

//handler处理消息Handler handler = new Handler(){        @Override        public void handleMessage(Message msg) {            //do something        } }; ...//sendMessage方法new Thread(new Runnable() {      @Override      public void run() {        Message message = handler.obtainMessage(1,"message");        handler.sendMessage(message);      }}).start();...//post方法handler.post(new Runnable() {       @Override       public void run() {         //do something       } });

先进入Handler类里面

首先,来看开Handler的构造方法。有很多,但其实只要关注其中的两个就好了

public Handler(Callback callback) {    this(callback, false);}public Handler(Looper looper) {   this(looper, null, false);}...

所有的构造函数都是调用一下两个构造函数

区别在于,一个使用主线程的Looper,一个可以自己指定Looper

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; } public Handler(Looper looper, Callback callback, boolean async) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = callback;        mAsynchronous = async;}

对成员的初始化,分别:

mLoopermQueuemCallbackmAsynchronous

所以,还需要涉及两个关键的类

Looper 和 MessageQueue


先看看sendMessage系列的方法和post系列的方法

这里写图片描述

这里写图片描述

public final boolean post(Runnable r){       return  sendMessageDelayed(getPostMessage(r), 0);}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); }public final boolean postDelayed(Runnable r, long delayMillis){        return sendMessageDelayed(getPostMessage(r), delayMillis);}public final boolean postAtFrontOfQueue(Runnable r){        return sendMessageAtFrontOfQueue(getPostMessage(r));}private static Message getPostMessage(Runnable r) {        Message m = Message.obtain();        m.callback = r;        return m;}

通过getPostMessage,把runnable接口封装在一个Message里面

这里的Post方法实际上是调用sendMessage系列的方法,传入封装好的Message

那么继续来看开sendMessage系列的方法

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

可以看到,以上所以的sendMessag的方法最后都会执行到sendMessageAtTime的这个

方法。

进入sendMessageAtTime方法,其中sendMessageAtFrontOfQueue跟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);}public final boolean sendMessageAtFrontOfQueue(Message msg) {        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, 0);}private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);}

最后,把msg放到队列里面!!!队列就是一开始初始化的mQueue。

再回头看看两个构造函数

 //获取主线程中Lopper,mQueue的初始化 mLooper = Looper.myLooper(); mQueue = mLooper.mQueue;//指定一个Looper,mQueue的初始化 mLooper = looper; mQueue = looper.mQueue;

所以,最后会把消息放入当前的Looper持有的队列里面

那么先来看看Looper这个类

Looper是用来使线程中的消息循环起来的。需要知道的是,首先我们要调用Looper的prepare方法,然后调用Looper的Loop方法。过程如下:

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

进入prepare方法

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)); }private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mThread = Thread.currentThread();} public static Looper myLooper() {        return sThreadLocal.get();}

通过 sThreadLocal.set()设置新的Looper,该Looper会持有一个新的队列。

需要注意的是,在一个线程中,只能调用一次Looper.prepare(),因为在第一次调用了Looper.prepare()之后,当前线程就已经绑定了Looper,在该线程内第二次调用Looper.prepare()方法的时候,sThreadLocal.get()会返回第一次调用prepare的时候绑定的Looper,不为null,这样就会抛出异常,throw new RuntimeException(“Only one Looper may be created per thread”),一个线程只能绑定一个Looper对象。

在AcitivityThread中已经执行Looper.prepare();Looper.loop();,所以我们可以直接调用myLooper()拿到looper,然后直接使用Handler就可以。

但是如果想在另一个线程使用Handler,那么就要重新调用 Looper.prepare();Looper.loop();

所以,Looper.prepare();是让当前线程绑定该Looper

接下来就会进入loop循环

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

把代码逻辑抽出来,简化后需要关注的关键代码

public static void loop() {        final Looper me = myLooper();        final MessageQueue queue = me.mQueue;        ...        for (;;) {            Message msg = queue.next(); // might block            ...            msg.target.dispatchMessage(msg);            ...            msg.recycleUnchecked();        }    }

逻辑清晰明了

  • 拿到当前线程绑定的Looper
  • 然后从Looper的队列里面拿出消息
  • 接着分发消息。
  • 最后回收这个Message

这里注意,queue.next()是会阻塞的。

所以,Looper持有一个队列,并且会一直loop循环从队列拿出消息。

接下来是进去到MessageQueue这个类里面了

先看看这个类的构造函数

MessageQueue(boolean quitAllowed) {        mQuitAllowed = quitAllowed;        mPtr = nativeInit();}private native static long nativeInit();

最后会调用到native方法,通过JNI直接和底层的代码打交道,深入底层的源码http://gityuan.com/2015/12/27/handler-message-native/。实际上是选择epoll的方式。

MessageQueue这个类里面有一个Message对象,用来作为队列。这个队列实际上是用链表来实现的。

来看看Message类中常用的部分成员和常用方法

public final class Message implements Parcelable {    public int what;    ...    public Object obj;    ....    Bundle data;    Handler target;    Runnable callback;    Message next;    private static final Object sPoolSync = new Object();    private static Message sPool;    private static int sPoolSize = 0;    private static final int MAX_POOL_SIZE = 50;    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();  }  void recycleUnchecked() {        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++;            }        }    } ...  public void setTarget(Handler target) {    this.target = target;  }  ...  public void sendToTarget() {    target.sendMessage(this);  }}

Message通过recycleUnchecked()对message进行回收,spool也是一个链表,把当前对象添加到链表前面,加入到消息池里面。然后可以通过obtain()在消息池里面拿到一个Message,最大值为50。这样,避免了频繁的创建对象和销毁对象了。

Message里面有一个target成员,用来绑定Handler。所以平时使用的 sendToTarget()实际上最后还是调用到Handler里面的sendMessage。

了解完Message的构造

那么回到正题,来主要关注到这一句代码!

Message msg = queue.next();

进入next()这个函数

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

源码很多,先简化一下,理清主要逻辑

Message next() {        ...        int pendingIdleHandlerCount = -1; // -1 only during first .        ...        for (;;) {            ...            nativePollOnce(ptr, nextPollTimeoutMillis);            synchronized (this) {                ...                Message prevMsg = null;                Message msg = mMessages;                if (msg != null && msg.target == null) {                    do {                        prevMsg = msg;                        msg = msg.next;                    } while (msg != null && !msg.isAsynchronous());                }                if (msg != null) {                        ....                        prevMsg.next = msg.next;                        msg.next = null;                        return msg;                } else {                    // No more messages.                    nextPollTimeoutMillis = -1;                }                nextPollTimeoutMillis = 0;       } }

现在逻辑已经很多清晰,

如果有msg就返回,nextPollTimeoutMillis = 0,那么在loop里面就继续执行

msg.target.dispatchMessage(msg);

msg.recycleUnchecked();

该msg绑定的Handler调用dispatchMessage(msg)把消息分发出去

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

如果有Runnable方法则执行handleCallback方法,最后会执行run方法。

private static void handleCallback(Message message) {        message.callback.run();}

否则就执行到我们重写的handleMessage(msg)了,msg就这样发送了过来。

否则如果没有消息,就 nextPollTimeoutMillis = -1

这个nextPollTimeoutMillis会传入到 nativePollOnce(ptr, nextPollTimeoutMillis)中

就会阻塞式地等待获取Message。这里又涉及到了native方法了http://gityuan.com/2015/12/27/handler-message-native/.

回过头再来看看入队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("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;    }

简化代码,最后的逻辑

boolean enqueueMessage(Message msg, long when) {        ...        synchronized (this) {            ...            msg.when = when;            Message p = mMessages;            ...            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 {                ...                Message prev;                for (;;) {                    prev = p;                    p = p.next;                    if (p == null || when < p.when) {                        break;                    }                }                msg.next = p; // invariant: p == prev.next                prev.next = msg;                .....            }            .....        }        return true;    }

入队实际上是把消息msg添加到链表最后面

0 0
原创粉丝点击