zoukankan      html  css  js  c++  java
  • Android核心类源码分析

    Handler流程
    1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
    2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
    3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
    4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
    5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。

    public final class Looper {
        //与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue
    
        private static final String TAG = "Looper";
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量
        private static Looper sMainLooper;  // guarded by Looper.class
        final MessageQueue mQueue;
        final Thread mThread;
        private Printer mLogging;
        private long mTraceTag;
    
        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 prepareMainLooper() {
            prepare(false);
            synchronized (Looper.class) {
                if (sMainLooper != null) {
                    throw new IllegalStateException("The main Looper has already been prepared.");
                }
                sMainLooper = myLooper();
            }
        }
    
        public static Looper getMainLooper() {
            synchronized (Looper.class) {
                return sMainLooper;
            }
        }
    
        //不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理
        public static void loop() {
            //返回了sThreadLocal存储的Looper实例 如果me为null则抛出异常,也就是说looper方法必须在prepare方法之后运行
            final Looper me = myLooper();
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            //拿到该looper实例中的mQueue(消息队列)
            final MessageQueue queue = me.mQueue;
    
            Binder.clearCallingIdentity();
            final long ident = Binder.clearCallingIdentity();
    
            //无限循环
            for (;;) {
                //取出一条消息,如果没有消息则阻塞
                Message msg = queue.next();
                if (msg == null) {
                    return;
                }
    
                final Printer logging = me.mLogging;
                if (logging != null) {
                    logging.println(">>>>> Dispatching to " + msg.target + " " +
                            msg.callback + ": " + msg.what);
                }
    
                final long traceTag = me.mTraceTag;
                if (traceTag != 0) {
                    Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
                }
                try {
                    //把消息交给msg的target的dispatchMessage方法去处理
                    msg.target.dispatchMessage(msg);
                } finally {
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
    
                if (logging != null) {
                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
                }
    
                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 @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    
        public static @NonNull MessageQueue myQueue() {
            return myLooper().mQueue;
        }
    
        //构造方法 创建了一个MessageQueue(消息队列)
        private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }
    
        public boolean isCurrentThread() {
            return Thread.currentThread() == mThread;
        }
    
        public void setMessageLogging(@Nullable Printer printer) {
            mLogging = printer;
        }
    
        public void setTraceTag(long traceTag) {
            mTraceTag = traceTag;
        }
    
        public void quit() {
            mQueue.quit(false);
        }
    
        public void quitSafely() {
            mQueue.quit(true);
        }
    
        public @NonNull Thread getThread() {
            return mThread;
        }
    
        public @NonNull MessageQueue getQueue() {
            return mQueue;
        }
    
        public void dump(@NonNull Printer pw, @NonNull String prefix) {
            pw.println(prefix + toString());
            mQueue.dump(pw, prefix + "  ");
        }
    
        @Override
        public String toString() {
            return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
                    + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
        }
    }
    public class Handler {
    
        private static final boolean FIND_POTENTIAL_LEAKS = false;
        private static final String TAG = "Handler";
    
        public interface Callback {
            public boolean handleMessage(Message msg);
        }
    
        //消息的最终回调是由我们控制的,我们在创建handler的时候都是复写handleMessage方法,然后根据msg.what进行消息处理。
        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);
            }
        }
    
        public Handler() {
            this(null, false);
        }
    
        public Handler(Callback callback) {
            this(callback, false);
        }
    
        public Handler(Looper looper) {
            this(looper, null, false);
        }
    
        public Handler(Looper looper, Callback callback) {
            this(looper, callback, false);
        }
    
        public Handler(boolean async) {
            this(null, async);
        }
    
        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());
                }
            }
    
            //获取了当前线程保存的Looper实例
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                        "Can't create handler inside thread that has not called Looper.prepare()");
            }
            //获取了这个Looper实例中保存的MessageQueue
            mQueue = mLooper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }
    
        public Handler(Looper looper, Callback callback, boolean async) {
            mLooper = looper;
            mQueue = looper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }
    
        public String getTraceName(Message message) {
            final StringBuilder sb = new StringBuilder();
            sb.append(getClass().getName()).append(": ");
            if (message.callback != null) {
                sb.append(message.callback.getClass().getName());
            } else {
                sb.append("#").append(message.what);
            }
            return sb.toString();
        }
    
        public String getMessageName(Message message) {
            if (message.callback != null) {
                return message.callback.getClass().getName();
            }
            return "0x" + Integer.toHexString(message.what);
        }
    
        public final Message obtainMessage() {
            return Message.obtain(this);
        }
    
        public final Message obtainMessage(int what) {
            return Message.obtain(this, what);
        }
    
        public final Message obtainMessage(int what, Object obj) {
            return Message.obtain(this, what, obj);
        }
    
        public final Message obtainMessage(int what, int arg1, int arg2) {
            return Message.obtain(this, what, arg1, arg2);
        }
    
        public final Message obtainMessage(int what, int arg1, int arg2, Object obj) {
            return Message.obtain(this, what, arg1, arg2, obj);
        }
    
        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));
        }
    
        public final boolean runWithScissors(final Runnable r, long timeout) {
            if (r == null) {
                throw new IllegalArgumentException("runnable must not be null");
            }
            if (timeout < 0) {
                throw new IllegalArgumentException("timeout must be non-negative");
            }
    
            if (Looper.myLooper() == mLooper) {
                r.run();
                return true;
            }
    
            BlockingRunnable br = new BlockingRunnable(r);
            return br.postAndWait(this, timeout);
        }
    
        public final void removeCallbacks(Runnable r) {
            mQueue.removeMessages(this, r, null);
        }
    
        public final void removeCallbacks(Runnable r, Object token) {
            mQueue.removeMessages(this, r, token);
        }
    
        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);
        }
    
        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);
        }
    
        //把当前的handler作为msg的target属性。最终会调用queue的enqueueMessage的方法,也就是说handler发出的消息,最终会保存到消息队列中去
        private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    
        public final void removeMessages(int what) {
            mQueue.removeMessages(this, what, null);
        }
    
        public final void removeMessages(int what, Object object) {
            mQueue.removeMessages(this, what, object);
        }
    
        public final void removeCallbacksAndMessages(Object token) {
            mQueue.removeCallbacksAndMessages(this, token);
        }
    
        public final boolean hasMessages(int what) {
            return mQueue.hasMessages(this, what, null);
        }
    
        public final boolean hasMessages(int what, Object object) {
            return mQueue.hasMessages(this, what, object);
        }
    
        public final boolean hasCallbacks(Runnable r) {
            return mQueue.hasMessages(this, r, null);
        }
    
        public final Looper getLooper() {
            return mLooper;
        }
    
        public final void dump(Printer pw, String prefix) {
            pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
            if (mLooper == null) {
                pw.println(prefix + "looper uninitialized");
            } else {
                mLooper.dump(pw, prefix + "  ");
            }
        }
    
        @Override
        public String toString() {
            return "Handler (" + getClass().getName() + ") {"
                    + Integer.toHexString(System.identityHashCode(this))
                    + "}";
        }
    
        final IMessenger getIMessenger() {
            synchronized (mQueue) {
                if (mMessenger != null) {
                    return mMessenger;
                }
                mMessenger = new MessengerImpl();
                return mMessenger;
            }
        }
    
        private final class MessengerImpl extends IMessenger.Stub {
            public void send(Message msg) {
                msg.sendingUid = Binder.getCallingUid();
                Handler.this.sendMessage(msg);
            }
        }
    
        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;
            return m;
        }
    
        private static void handleCallback(Message message) {
            message.callback.run();
        }
    
        final Looper mLooper;
        final MessageQueue mQueue;
        final Callback mCallback;
        final boolean mAsynchronous;
        IMessenger mMessenger;
    
        private static final class BlockingRunnable implements Runnable {
            private final Runnable mTask;
            private boolean mDone;
    
            public BlockingRunnable(Runnable task) {
                mTask = task;
            }
    
            @Override
            public void run() {
                try {
                    mTask.run();
                } finally {
                    synchronized (this) {
                        mDone = true;
                        notifyAll();
                    }
                }
            }
    
            public boolean postAndWait(Handler handler, long timeout) {
                if (!handler.post(this)) {
                    return false;
                }
    
                synchronized (this) {
                    if (timeout > 0) {
                        final long expirationTime = SystemClock.uptimeMillis() + timeout;
                        while (!mDone) {
                            long delay = expirationTime - SystemClock.uptimeMillis();
                            if (delay <= 0) {
                                return false; // timeout
                            }
                            try {
                                wait(delay);
                            } catch (InterruptedException ex) {
                            }
                        }
                    } else {
                        while (!mDone) {
                            try {
                                wait();
                            } catch (InterruptedException ex) {
                            }
                        }
                    }
                }
                return true;
            }
        }
    
    }
    public final class MessageQueue {
        private static final String TAG = "MessageQueue";
        private static final boolean DEBUG = false;
        private final boolean mQuitAllowed;
    
        @SuppressWarnings("unused")
        private long mPtr; // used by native code
    
        Message mMessages;
        private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
        private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
        private IdleHandler[] mPendingIdleHandlers;
        private boolean mQuitting;
        private boolean mBlocked;
    
        private int mNextBarrierToken;
    
        private native static long nativeInit();
    
        private native static void nativeDestroy(long ptr);
    
        private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
    
        private native static void nativeWake(long ptr);
    
        private native static boolean nativeIsPolling(long ptr);
    
        private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
    
        MessageQueue(boolean quitAllowed) {
            mQuitAllowed = quitAllowed;
            mPtr = nativeInit();
        }
    
        @Override
        protected void finalize() throws Throwable {
            try {
                dispose();
            } finally {
                super.finalize();
            }
        }
    
        private void dispose() {
            if (mPtr != 0) {
                nativeDestroy(mPtr);
                mPtr = 0;
            }
        }
    
        public boolean isIdle() {
            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                return mMessages == null || now < mMessages.when;
            }
        }
    
        public void addIdleHandler(@NonNull IdleHandler handler) {
            if (handler == null) {
                throw new NullPointerException("Can't add a null IdleHandler");
            }
            synchronized (this) {
                mIdleHandlers.add(handler);
            }
        }
    
        public void removeIdleHandler(@NonNull IdleHandler handler) {
            synchronized (this) {
                mIdleHandlers.remove(handler);
            }
        }
    
        public boolean isPolling() {
            synchronized (this) {
                return isPollingLocked();
            }
        }
    
        private boolean isPollingLocked() {
            return !mQuitting && nativeIsPolling(mPtr);
        }
    
        public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
                                                     @OnFileDescriptorEventListener.Events int events,
                                                     @NonNull OnFileDescriptorEventListener listener) {
            if (fd == null) {
                throw new IllegalArgumentException("fd must not be null");
            }
            if (listener == null) {
                throw new IllegalArgumentException("listener must not be null");
            }
    
            synchronized (this) {
                updateOnFileDescriptorEventListenerLocked(fd, events, listener);
            }
        }
    
        public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
            if (fd == null) {
                throw new IllegalArgumentException("fd must not be null");
            }
    
            synchronized (this) {
                updateOnFileDescriptorEventListenerLocked(fd, 0, null);
            }
        }
    
        private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
                                                               OnFileDescriptorEventListener listener) {
            final int fdNum = fd.getInt$();
    
            int index = -1;
            FileDescriptorRecord record = null;
            if (mFileDescriptorRecords != null) {
                index = mFileDescriptorRecords.indexOfKey(fdNum);
                if (index >= 0) {
                    record = mFileDescriptorRecords.valueAt(index);
                    if (record != null && record.mEvents == events) {
                        return;
                    }
                }
            }
    
            if (events != 0) {
                events |= OnFileDescriptorEventListener.EVENT_ERROR;
                if (record == null) {
                    if (mFileDescriptorRecords == null) {
                        mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
                    }
                    record = new FileDescriptorRecord(fd, events, listener);
                    mFileDescriptorRecords.put(fdNum, record);
                } else {
                    record.mListener = listener;
                    record.mEvents = events;
                    record.mSeq += 1;
                }
                nativeSetFileDescriptorEvents(mPtr, fdNum, events);
            } else if (record != null) {
                record.mEvents = 0;
                mFileDescriptorRecords.removeAt(index);
            }
        }
    
        private int dispatchEvents(int fd, int events) {
            // Get the file descriptor record and any state that might change.
            final FileDescriptorRecord record;
            final int oldWatchedEvents;
            final OnFileDescriptorEventListener listener;
            final int seq;
            synchronized (this) {
                record = mFileDescriptorRecords.get(fd);
                if (record == null) {
                    return 0; // spurious, no listener registered
                }
    
                oldWatchedEvents = record.mEvents;
                events &= oldWatchedEvents; // filter events based on current watched set
                if (events == 0) {
                    return oldWatchedEvents; // spurious, watched events changed
                }
    
                listener = record.mListener;
                seq = record.mSeq;
            }
    
            int newWatchedEvents = listener.onFileDescriptorEvents(
                    record.mDescriptor, events);
            if (newWatchedEvents != 0) {
                newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
            }
    
            if (newWatchedEvents != oldWatchedEvents) {
                synchronized (this) {
                    int index = mFileDescriptorRecords.indexOfKey(fd);
                    if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
                            && record.mSeq == seq) {
                        record.mEvents = newWatchedEvents;
                        if (newWatchedEvents == 0) {
                            mFileDescriptorRecords.removeAt(index);
                        }
                    }
                }
            }
    
            return newWatchedEvents;
        }
    
        Message next() {
            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 (DEBUG) Log.v(TAG, "Returning message: " + msg);
                            msg.markInUse();
                            return msg;
                        }
                    } else {
                        nextPollTimeoutMillis = -1;
                    }
    
                    if (mQuitting) {
                        dispose();
                        return null;
                    }
    
                    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);
                }
    
                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(TAG, "IdleHandler threw exception", t);
                    }
    
                    if (!keep) {
                        synchronized (this) {
                            mIdleHandlers.remove(idler);
                        }
                    }
                }
    
                pendingIdleHandlerCount = 0;
                nextPollTimeoutMillis = 0;
            }
        }
    
        void quit(boolean safe) {
            if (!mQuitAllowed) {
                throw new IllegalStateException("Main thread not allowed to quit.");
            }
    
            synchronized (this) {
                if (mQuitting) {
                    return;
                }
                mQuitting = true;
    
                if (safe) {
                    removeAllFutureMessagesLocked();
                } else {
                    removeAllMessagesLocked();
                }
    
                // We can assume mPtr != 0 because mQuitting was previously false.
                nativeWake(mPtr);
            }
        }
    
    
        public int postSyncBarrier() {
            return postSyncBarrier(SystemClock.uptimeMillis());
        }
    
        private int postSyncBarrier(long when) {
            synchronized (this) {
                final int token = mNextBarrierToken++;
                final Message msg = Message.obtain();
                msg.markInUse();
                msg.when = when;
                msg.arg1 = token;
    
                Message prev = null;
                Message p = mMessages;
                if (when != 0) {
                    while (p != null && p.when <= when) {
                        prev = p;
                        p = p.next;
                    }
                }
                if (prev != null) { // invariant: p == prev.next
                    msg.next = p;
                    prev.next = msg;
                } else {
                    msg.next = p;
                    mMessages = msg;
                }
                return token;
            }
        }
    
        public void removeSyncBarrier(int token) {
            synchronized (this) {
                Message prev = null;
                Message p = mMessages;
                while (p != null && (p.target != null || p.arg1 != token)) {
                    prev = p;
                    p = p.next;
                }
                if (p == null) {
                    throw new IllegalStateException("The specified message queue synchronization "
                            + " barrier token has not been posted or has already been removed.");
                }
                final boolean needWake;
                if (prev != null) {
                    prev.next = p.next;
                    needWake = false;
                } else {
                    mMessages = p.next;
                    needWake = mMessages == null || mMessages.target != null;
                }
                p.recycleUnchecked();
    
                if (needWake && !mQuitting) {
                    nativeWake(mPtr);
                }
            }
        }
    
        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.getMessage(), e);
                    msg.recycle();
                    return false;
                }
    
                msg.markInUse();
                msg.when = when;
                Message p = mMessages;
                boolean needWake;
                if (p == null || when == 0 || when < p.when) {
                    msg.next = p;
                    mMessages = msg;
                    needWake = mBlocked;
                } else {
                    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;
                }
    
                if (needWake) {
                    nativeWake(mPtr);
                }
            }
            return true;
        }
    
        boolean hasMessages(Handler h, int what, Object object) {
            if (h == null) {
                return false;
            }
    
            synchronized (this) {
                Message p = mMessages;
                while (p != null) {
                    if (p.target == h && p.what == what && (object == null || p.obj == object)) {
                        return true;
                    }
                    p = p.next;
                }
                return false;
            }
        }
    
        boolean hasMessages(Handler h, Runnable r, Object object) {
            if (h == null) {
                return false;
            }
    
            synchronized (this) {
                Message p = mMessages;
                while (p != null) {
                    if (p.target == h && p.callback == r && (object == null || p.obj == object)) {
                        return true;
                    }
                    p = p.next;
                }
                return false;
            }
        }
    
        void removeMessages(Handler h, int what, Object object) {
            if (h == null) {
                return;
            }
    
            synchronized (this) {
                Message p = mMessages;
    
                while (p != null && p.target == h && p.what == what
                        && (object == null || p.obj == object)) {
                    Message n = p.next;
                    mMessages = n;
                    p.recycleUnchecked();
                    p = n;
                }
    
                while (p != null) {
                    Message n = p.next;
                    if (n != null) {
                        if (n.target == h && n.what == what
                                && (object == null || n.obj == object)) {
                            Message nn = n.next;
                            n.recycleUnchecked();
                            p.next = nn;
                            continue;
                        }
                    }
                    p = n;
                }
            }
        }
    
        void removeMessages(Handler h, Runnable r, Object object) {
            if (h == null || r == null) {
                return;
            }
    
            synchronized (this) {
                Message p = mMessages;
    
                while (p != null && p.target == h && p.callback == r
                        && (object == null || p.obj == object)) {
                    Message n = p.next;
                    mMessages = n;
                    p.recycleUnchecked();
                    p = n;
                }
    
                while (p != null) {
                    Message n = p.next;
                    if (n != null) {
                        if (n.target == h && n.callback == r
                                && (object == null || n.obj == object)) {
                            Message nn = n.next;
                            n.recycleUnchecked();
                            p.next = nn;
                            continue;
                        }
                    }
                    p = n;
                }
            }
        }
    
        void removeCallbacksAndMessages(Handler h, Object object) {
            if (h == null) {
                return;
            }
    
            synchronized (this) {
                Message p = mMessages;
    
                while (p != null && p.target == h
                        && (object == null || p.obj == object)) {
                    Message n = p.next;
                    mMessages = n;
                    p.recycleUnchecked();
                    p = n;
                }
    
                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;
                }
            }
        }
    
        private void removeAllMessagesLocked() {
            Message p = mMessages;
            while (p != null) {
                Message n = p.next;
                p.recycleUnchecked();
                p = n;
            }
            mMessages = null;
        }
    
        private void removeAllFutureMessagesLocked() {
            final long now = SystemClock.uptimeMillis();
            Message p = mMessages;
            if (p != null) {
                if (p.when > now) {
                    removeAllMessagesLocked();
                } else {
                    Message n;
                    for (; ; ) {
                        n = p.next;
                        if (n == null) {
                            return;
                        }
                        if (n.when > now) {
                            break;
                        }
                        p = n;
                    }
                    p.next = null;
                    do {
                        p = n;
                        n = p.next;
                        p.recycleUnchecked();
                    } while (n != null);
                }
            }
        }
    
        void dump(Printer pw, String prefix) {
            synchronized (this) {
                long now = SystemClock.uptimeMillis();
                int n = 0;
                for (Message msg = mMessages; msg != null; msg = msg.next) {
                    pw.println(prefix + "Message " + n + ": " + msg.toString(now));
                    n++;
                }
                pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
                        + ", quitting=" + mQuitting + ")");
            }
        }
    
        public static interface IdleHandler {
            boolean queueIdle();
        }
    
        public interface OnFileDescriptorEventListener {
    
            public static final int EVENT_INPUT = 1 << 0;
            public static final int EVENT_OUTPUT = 1 << 1;
            public static final int EVENT_ERROR = 1 << 2;
    
            /**
             * @hide
             */
            @Retention(RetentionPolicy.SOURCE)
            @IntDef(flag = true, value = {EVENT_INPUT, EVENT_OUTPUT, EVENT_ERROR})
            public @interface Events {
            }
    
            @Events
            int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
        }
    
        private static final class FileDescriptorRecord {
            public final FileDescriptor mDescriptor;
            public int mEvents;
            public OnFileDescriptorEventListener mListener;
            public int mSeq;
    
            public FileDescriptorRecord(FileDescriptor descriptor,
                                        int events, OnFileDescriptorEventListener listener) {
                mDescriptor = descriptor;
                mEvents = events;
                mListener = listener;
            }
        }
    }
    public class Message implements Parcelable {
    
        public int what;
        public int arg1;
        public int arg2;
    
        public Object obj;
        public Messenger replyTo;
    
        public int sendingUid = -1;
    
        /*package*/ static final int FLAG_IN_USE = 1 << 0;
        /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
        /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
        /*package*/ int flags;
        /*package*/ long when;
        /*package*/ Bundle data;
        /*package*/ Handler target;
        /*package*/ Runnable callback;
        /*package*/ 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;
        private static boolean gCheckRecycle = true;
    
        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();
        }
    
        public static Message obtain(Message orig) {
            Message m = obtain();
            m.what = orig.what;
            m.arg1 = orig.arg1;
            m.arg2 = orig.arg2;
            m.obj = orig.obj;
            m.replyTo = orig.replyTo;
            m.sendingUid = orig.sendingUid;
            if (orig.data != null) {
                m.data = new Bundle(orig.data);
            }
            m.target = orig.target;
            m.callback = orig.callback;
    
            return m;
        }
    
        public static Message obtain(Handler h) {
            Message m = obtain();
            m.target = h;
    
            return m;
        }
    
        public static Message obtain(Handler h, Runnable callback) {
            Message m = obtain();
            m.target = h;
            m.callback = callback;
    
            return m;
        }
    
        public static Message obtain(Handler h, int what) {
            Message m = obtain();
            m.target = h;
            m.what = what;
    
            return m;
        }
    
        public static Message obtain(Handler h, int what, Object obj) {
            Message m = obtain();
            m.target = h;
            m.what = what;
            m.obj = obj;
    
            return m;
        }
    
        public static Message obtain(Handler h, int what, int arg1, int arg2) {
            Message m = obtain();
            m.target = h;
            m.what = what;
            m.arg1 = arg1;
            m.arg2 = arg2;
    
            return m;
        }
    
        public static Message obtain(Handler h, int what,
                                     int arg1, int arg2, Object obj) {
            Message m = obtain();
            m.target = h;
            m.what = what;
            m.arg1 = arg1;
            m.arg2 = arg2;
            m.obj = obj;
    
            return m;
        }
    
        public static void updateCheckRecycle(int targetSdkVersion) {
            if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
                gCheckRecycle = false;
            }
        }
    
        public void recycle() {
            if (isInUse()) {
                if (gCheckRecycle) {
                    throw new IllegalStateException("This message cannot be recycled because it "
                            + "is still in use.");
                }
                return;
            }
            recycleUnchecked();
        }
    
        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 copyFrom(Message o) {
            this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
            this.what = o.what;
            this.arg1 = o.arg1;
            this.arg2 = o.arg2;
            this.obj = o.obj;
            this.replyTo = o.replyTo;
            this.sendingUid = o.sendingUid;
    
            if (o.data != null) {
                this.data = (Bundle) o.data.clone();
            } else {
                this.data = null;
            }
        }
    
        public long getWhen() {
            return when;
        }
    
        public void setTarget(Handler target) {
            this.target = target;
        }
    
        public Handler getTarget() {
            return target;
        }
    
        public Runnable getCallback() {
            return callback;
        }
    
        public Bundle getData() {
            if (data == null) {
                data = new Bundle();
            }
    
            return data;
        }
    
        public Bundle peekData() {
            return data;
        }
    
        public void setData(Bundle data) {
            this.data = data;
        }
    
        public void sendToTarget() {
            target.sendMessage(this);
        }
    
        public boolean isAsynchronous() {
            return (flags & FLAG_ASYNCHRONOUS) != 0;
        }
    
        public void setAsynchronous(boolean async) {
            if (async) {
                flags |= FLAG_ASYNCHRONOUS;
            } else {
                flags &= ~FLAG_ASYNCHRONOUS;
            }
        }
    
        /*package*/ boolean isInUse() {
            return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
        }
    
        /*package*/ void markInUse() {
            flags |= FLAG_IN_USE;
        }
    
        public Message() {
        }
    
        @Override
        public String toString() {
            return toString(SystemClock.uptimeMillis());
        }
    
        String toString(long now) {
            StringBuilder b = new StringBuilder();
            b.append("{ when=");
            TimeUtils.formatDuration(when - now, b);
    
            if (target != null) {
                if (callback != null) {
                    b.append(" callback=");
                    b.append(callback.getClass().getName());
                } else {
                    b.append(" what=");
                    b.append(what);
                }
    
                if (arg1 != 0) {
                    b.append(" arg1=");
                    b.append(arg1);
                }
    
                if (arg2 != 0) {
                    b.append(" arg2=");
                    b.append(arg2);
                }
    
                if (obj != null) {
                    b.append(" obj=");
                    b.append(obj);
                }
    
                b.append(" target=");
                b.append(target.getClass().getName());
            } else {
                b.append(" barrier=");
                b.append(arg1);
            }
    
            b.append(" }");
            return b.toString();
        }
    
        public static final Parcelable.Creator<Message> CREATOR
                = new Parcelable.Creator<Message>() {
            public Message createFromParcel(Parcel source) {
                Message msg = Message.obtain();
                msg.readFromParcel(source);
                return msg;
            }
    
            public Message[] newArray(int size) {
                return new Message[size];
            }
        };
    
        public int describeContents() {
            return 0;
        }
    
        public void writeToParcel(Parcel dest, int flags) {
            if (callback != null) {
                throw new RuntimeException(
                        "Can't marshal callbacks across processes.");
            }
            dest.writeInt(what);
            dest.writeInt(arg1);
            dest.writeInt(arg2);
            if (obj != null) {
                try {
                    Parcelable p = (Parcelable) obj;
                    dest.writeInt(1);
                    dest.writeParcelable(p, flags);
                } catch (ClassCastException e) {
                    throw new RuntimeException(
                            "Can't marshal non-Parcelable objects across processes.");
                }
            } else {
                dest.writeInt(0);
            }
            dest.writeLong(when);
            dest.writeBundle(data);
            Messenger.writeMessengerOrNullToParcel(replyTo, dest);
            dest.writeInt(sendingUid);
        }
    
        private void readFromParcel(Parcel source) {
            what = source.readInt();
            arg1 = source.readInt();
            arg2 = source.readInt();
            if (source.readInt() != 0) {
                obj = source.readParcelable(getClass().getClassLoader());
            }
            when = source.readLong();
            data = source.readBundle();
            replyTo = Messenger.readMessengerOrNullFromParcel(source);
            sendingUid = source.readInt();
        }
    }
  • 相关阅读:
    BubbleGum96 开箱杂谈与软件资源
    Intel Edision —— 从SSH无法连接到systemd
    Intel Edision —— 开发环境选择一贴通
    Intel Edision —— 上电、基本设置与系统初探
    使用RPi-Monitor监控、统计Guitar的运行状态
    吃我一记咸鱼突刺——使用板载RTC定时开机
    Intel Edison —— 控制GPIO接口,网页显示传感器数值
    docker on UP Board
    Android源码分析--CircleImageView 源码详解
    如何自定义一个优雅的ContentProvider
  • 原文地址:https://www.cnblogs.com/huanyi0723/p/6282138.html
Copyright © 2011-2022 走看看