Handler源码解析

来源:互联网 发布:网络危害 编辑:程序博客网 时间:2024/05/20 19:30

主线程的Looper初始化是在类ActivityThread初始化的,main函数里,这也是AndroidApp里一个进程初始化就进来的地方。

Process.setArgV0("<pre-initialized>");Looper.prepareMainLooper();ActivityThread thread = new ActivityThread();thread.attach(false);if (sMainThreadHandler == null) {    sMainThreadHandler = thread.getHandler();}AsyncTask.init();if (false) {    Looper.myLooper().setMessageLogging(new            LogPrinter(Log.DEBUG, "ActivityThread"));}Looper.loop();
Handler涉及Looper,MessageQueue,Message类,为什么一开始在新的线程需要初始化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;}
Handler在初始化的时候会判断当前线程有无Looper,若有则赋值,没有就抛异常。在这里还需要说下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));}
private Looper(boolean quitAllowed) {    mQueue = new MessageQueue(quitAllowed);    mThread = Thread.currentThread();}

sThreadLocal是ThreadLocal类,专门用于多线程开发,这样每个线程的ThreadLocal值都不同,属于一个复制类。

接下来Looper就开始从MessageQueue循环取消息,也就是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;        }
queue.next在取不到值时,会阻塞。

接下来说明下Handler发送消息时做了什么。

/** * 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();}
这是取得一个消息,建议用obtain来取,这里会循环利用生成的50个消息,如果当前没有可利用的消息,就生成一个,Message还是Parcelable,可用于进程间传递消息
msg.target = this;if (mAsynchronous) {    msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);
在这里就设置msg的处理目标为当前Handler,并插入到MessageQueue里,在这里要注意是按照需要什么时候处理的时间排序的,因为可用postOnDelay()延时发送。
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);}
这时候如果在阻塞,也就是没有取到消息处理,一直在循环,mBlocked就为thue,如果when为0,就插入到头部,唤醒next(),如果when不为0,就插入到比它大的前面。
final long ptr = mPtr;if (ptr == 0) {    return null;}int pendingIdleHandlerCount = -1; // -1 only during first iterationint 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;}
这就是MessageQueue的next函数,一开始没消息,就会一直循环,当有消息时,就取出第一条消息,并与当前时间比较,如果当前时间小于消息的时间,就continue循环,这时会进入阻塞阶段,
 nativePollOnce(ptr, nextPollTimeoutMillis);
否则就返回消息,这时就交给looper处理
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the 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();    }}
说到Handler,就要说到Handler如果处理不当,容易导致Activity或者与它相关的类没有及时回收,这时会导致OOM。

这时延时发送了,因为handler引用了当前Activity,如果不取消息,Activity就一直有引用,导致虽然调用了onDestroy()但是无法回收。通过取消与Handler相关的消息,这样就可以把引用关系给消除。

void removeCallbacksAndMessages(Handler h, Object object) {    if (h == null) {        return;    }    synchronized (this) {        Message p = mMessages;        // Remove all messages at front.        while (p != null && p.target == h                && (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 && (object == null || n.obj == object)) {                    Message nn = n.next;                    n.recycleUnchecked();                    p.next = nn;                    continue;                }            }            p = n;        }    }}
在这里有个更省事的例子,就是WeakHandler,外国人就是牛逼,

博客是:https://techblog.badoo.com/blog/2014/08/28/android-handler-memory-leaks

github是:https://github.com/badoo/android-weak-handler

0 0
原创粉丝点击