美文网首页
Android handler

Android handler

作者: 折剑游侠 | 来源:发表于2019-12-31 16:27 被阅读0次

    android开发的话现在handler应该都倒背如流了

    handler发送message到message queue,looper 轮询 message queue,取到message后回调handleMessage方法。之前面试我也都是这么背的=。=

    然后面试官会问到:handler是怎么发送message到message queue的呢,一个线程只对应一个looper吗,Looper是什么时候开始轮询的呢,子线程可以用hander吗,主线程调用Looper.loop()为什么不会卡死,知道同步障碍吗等。下面翻翻源码,从写代码的角度来讲先要new handler。

    handler构造方法

    //handler的成员变量
    final Looper mLooper;
    final MessageQueue mQueue;
    final Callback mCallback;
    final boolean mAsynchronous;
    
    public interface Callback {
            public boolean handleMessage(Message 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());
                }
            }
    
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread " + Thread.currentThread()
                            + " 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;
        }
    

    构造方法最多有三个参数,无论哪个构造方法最后都会给mLooper赋值。

    • callback:消息回调。
    • async:是否为异步消息。
    • mQueue:赋值调用looper.mQueue()

    结论:handler持有Looper和MessageQueue。

    主线程中我习惯这样写

    private val handler = Handler(Looper.getMainLooper())
    

    调用的构造方法

    public Handler(Looper looper) {
            this(looper, null, false);
        }
    
    public Handler(Looper looper, Callback callback, boolean async) {
            mLooper = looper;
            mQueue = looper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }
    

    callback不传默认为null,async默认为false。

    callback调用处

    //Handler类方法,继承Handler重写的方法,接收消息回调。
    public void handleMessage(Message msg) {}
    //msg callback
    private static void handleCallback(Message message) {
            message.callback.run();
        }
    
    //首先判断Message的callback,不为空直接调用上面的handleCallback。
    //为空再判断构造方法是否传了callback,传了调用callback回调,没传调用上面handleMessage()
    //继承Handler的写法需要重写handleMessage()处理消息回调。
    public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    handler会绑定到looper,如果构造方法没传looper呢?接下来看不传looper的构造方法。

    public Handler() {
            this(null, false);
    }
    
    public Handler(Callback callback, boolean async) {
            if (FIND_POTENTIAL_LEAKS) {
                final Class<? extends Handler> klass = getClass();
                if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                        (klass.getModifiers() & Modifier.STATIC) == 0) {
                    Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                        klass.getCanonicalName());
                }
            }
    
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread " + Thread.currentThread()
                            + " that has not called Looper.prepare()");
            }
            mQueue = mLooper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
    }
    

    Looper.myLooper()

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
    public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
    }
    

    ThreadLocal具体实现这里就不展开了。简单来说,ThreadLocal会在不同线程保存不同的实例,那么这也解释了一个线程只对应一个looper。主线程中初始化Handler,不传looper的情况下,通过Looper.myLooper()取到ThreadLocal中对应的主线程looper实例。那么主线程的looper何时初始化存到ThreadLocal中呢。这里说结论,app初始化的时候ActivityThread.main()中调用Looper.prepareMainLooper(),初始化了主线程Looper。

    //ActivityThread.main()
    public static void main(String[] args) {
            ......
            Looper.prepareMainLooper();
            ......
            Looper.loop();
    }
    

    Looper.prepare()

    public static void prepare() {
            prepare(true);
        }
    
    public static void prepareMainLooper() {
            prepare(false);
            synchronized (Looper.class) {
                if (sMainLooper != null) {
                    throw new IllegalStateException("The main Looper has already been prepared.");
                }
                sMainLooper = myLooper();
            }
        }
    
    //都会调用到此方法 quitAllowed是否可以取消、停止轮询。
    //prepareMainLooper传的false,因为要保证app一直运行。
    private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                //一个线程只能创建一个looper
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            //初始化Looper
            sThreadLocal.set(new Looper(quitAllowed));
        }
    

    Looper构造方法中初始化了MessageQueue,对应上了前面Handler构造方法中的looper.mQueue()

    private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }
    

    MessageQueue

    MessageQueue(boolean quitAllowed) {
            mQuitAllowed = quitAllowed;
            mPtr = nativeInit();
    }
    
    void quit(boolean safe) {
            if (!mQuitAllowed) {
                //prepareMainLooper传的false,主线程调用quit()会抛出下面异常
                //子线程调用quit()走下面removeMessages()相关方法
                throw new IllegalStateException("Main thread not allowed to quit.");
            }
    
            synchronized (this) {
                if (mQuitting) {
                    return;
                }
                mQuitting = true;
    
                if (safe) {
                    removeAllFutureMessagesLocked();
                } else {
                    removeAllMessagesLocked();
                }
                nativeWake(mPtr);
            }
    }
    

    在子线程中创建handler手动调用Looper.prepare(),其实就是创建子线程对应的Looper,Looper构造方法又初始化了MessageQueue。Handler,Looper,MessageQueue都创建好了,接下来调用Looper.loop()开启轮询。主线程中无需调用也是因为ActivityThread中已经调用过了。

    public static void loop() {
            final Looper me = myLooper();
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            ......
            //MessageQueue.next()
            for (;;) {
                Message msg = queue.next();
                if (msg == null) {
                    return;
                }
                //msg.target是Handler,调用Handler.dispatchMessage()完成消息回调。
                msg.target.dispatchMessage(msg);
            }
            ......
    }
    

    处理消息是在MessageQueue.next()方法。先解决上一个问题,handler怎么把message发送到MessageQueue中。

    Handler.sendMessage()调用链

    public final boolean sendMessage(Message msg) {
            return sendMessageDelayed(msg, 0);
    }
    
    //delayMillis不传或小于0置为0,默认无延迟
    public final boolean sendMessageDelayed(Message msg, long delayMillis){
            if (delayMillis < 0) {
                delayMillis = 0;
            }
            return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    
    //mQueue传递到enqueueMessage()
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            if (queue == null) {
                //无MessageQueue抛出异常
                RuntimeException e = new RuntimeException(
                        this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
                return false;
            }
            return enqueueMessage(queue, msg, uptimeMillis);
    }
    
    //调用MessageQueue.enqueueMessage()
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            //Handler构造方法中的参数async
            if (mAsynchronous) {
                //调用了Message的setAsynchronous方法
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
    }
    
    //Message.setAsynchronous(),操作Message的状态flags,位操作。
    public void setAsynchronous(boolean async) {
            if (async) {
                flags |= FLAG_ASYNCHRONOUS;
            } else {
                flags &= ~FLAG_ASYNCHRONOUS;
            }
        }
    

    MessageQueue.enqueueMessage()

    boolean enqueueMessage(Message msg, long when) {
            if (msg.target == null) {
                throw new IllegalArgumentException("Message must have a target.");
            }
            //判断Message的flags中是否有FLAG_IN_USE标记,可用状态。
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }
    
            synchronized (this) {
                //Thread dead状态抛异常
                if (mQuitting) {
                    IllegalStateException e = new IllegalStateException(
                            msg.target + " sending message to a Handler on a dead thread");
                    //Message.recycle()调用Message.recycleUnchecked(),回收message到消息池,重置message参数。
                    msg.recycle();
                    return false;
                }
    
                //flags增加FLAG_IN_USE状态
                msg.markInUse();
                msg.when = when;
                Message p = mMessages;
                //是否需要唤醒
                boolean needWake;
                if (p == null || when == 0 || when < p.when) {
                    //message是链表结构,mMessages为null说明是空链表,新message在头部。
                    //message.when == 0或者when < p.when,when值大小有优先级,小的放前面。
                    msg.next = p;
                    mMessages = msg;
                    needWake = mBlocked;
                } else {
                    needWake = mBlocked && p.target == null && msg.isAsynchronous();
                    Message prev;
                    for (;;) {
                        //mMessages不为空,将message插到上一条消息的后面。
                        prev = p;
                        p = p.next;
                        if (p == null || when < p.when) {
                            break;
                        }
                        if (needWake && p.isAsynchronous()) {
                            needWake = false;
                        }
                    }
                    msg.next = p;
                    prev.next = msg;
                }
    
                if (needWake) {
                    nativeWake(mPtr);
                }
            }
            return true;
    }
    

    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++;
                }
            }
    }
    
    boolean isInUse() {
            return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
    }
    
    void markInUse() {
            flags |= FLAG_IN_USE;
    }
    

    handler.sendMessage()调用MessageQueue.enqueueMessage()将message插入message链表。链表中无消息放表头,有消息按when值大小,小的放前面。回到取消息的地方MessageQueue.next()

     Message next() {
            int pendingIdleHandlerCount = -1;
            int nextPollTimeoutMillis = 0;
            for (;;) {
                if (nextPollTimeoutMillis != 0) {
                    Binder.flushPendingCommands();
                }
                nativePollOnce(ptr, nextPollTimeoutMillis);
    
                synchronized (this) {
                    final long now = SystemClock.uptimeMillis();
                    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) {
                        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 {
                            mBlocked = false;
                            if (prevMsg != null) {
                                prevMsg.next = msg.next;
                            } else {
                                mMessages = msg.next;
                            }
                            msg.next = null;
                            msg.markInUse();
                            //获取message返回给looper
                            return msg;
                        }
                    } else {
                        nextPollTimeoutMillis = -1;
                    }
            }
        }
    }
    

    前面handler.sendMessage()调用msg.setAsynchronous(true)

     public void setAsynchronous(boolean async) {
            if (async) {
                flags |= FLAG_ASYNCHRONOUS;
            } else {
                flags &= ~FLAG_ASYNCHRONOUS;
            }
    }
    
    //判断异步消息
    public boolean isAsynchronous() {
            return (flags & FLAG_ASYNCHRONOUS) != 0;
    }
    

    MessageQueue.next()对异步消息进行优先处理

    MessageQueue.postSyncBarrier()

    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) {
                    msg.next = p;
                    prev.next = msg;
                } else {
                    msg.next = p;
                    mMessages = msg;
                }
                return token;
            }
    }
    

    开启同步障碍即调用MessageQueue.postSyncBarrier()发送异步消息,相当于开个后门,处理要紧事情。ViewRootImpl.scheduleTraversals()调用了MessageQueue.postSyncBarrier()发送异步消息开始绘制ui。Android系统为了保证ui绘制机制的优先度,防止画面卡顿,开启了同步障碍。

    void scheduleTraversals() {
            if (!mTraversalScheduled) {
                mTraversalScheduled = true;
                mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
                mChoreographer.postCallback(
                        Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
                if (!mUnbufferedInputDispatch) {
                    scheduleConsumeBatchedInput();
                }
                notifyRendererOfFramePending();
                pokeDrawLockIfNeeded();
            }
    }
    

    最后一个点,Looper.loop()为什么不会卡死。简单来说就是Linux pipe/epoll机制。无消息时阻塞在nativePollOnce()方法,释放资源,有消息时唤醒。

    Android中为什么主线程不会因为Looper.loop()里的死循环卡死?

    相关文章

      网友评论

          本文标题:Android handler

          本文链接:https://www.haomeiwen.com/subject/yafboctx.html