Handler/Looper/Message常见问题

2023-07-31  本文已影响0人  孔鹏飞

如何判断当前线程是否为主线程?

    public static boolean isMainThread() {
        return Looper.getMainLooper().getThread() == Thread.currentThread();
    }

如何创建异步Handler?

异步Handler发送的消息为异步消息,不受同步屏障(synchronization barriers)的约束。

    public static Handler createAsync(@NonNull Looper looper) {
        if (Build.VERSION.SDK_INT >= 28) {
            return Handler.createAsync(looper);
        }
        if (Build.VERSION.SDK_INT >= 16) {
            try {
                return Handler.class.getDeclaredConstructor(Looper.class, Handler.Callback.class, boolean.class)
                        .newInstance(looper, null, true);
            } catch (IllegalAccessException ignored) {
            } catch (InstantiationException ignored) {
            } catch (NoSuchMethodException ignored) {
            } catch (InvocationTargetException e) {
                return new Handler(looper);
            }
        }
        return new Handler(looper);
    }

Message的复用机制

复用机制通过Message.obtain()方法来实现,它会从一个消息池中获取可用的Message对象,而不是每次都创建新的对象。

    // Handler.java
    public 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();
    }

那么消息是什么时候被添加到消息池sPool中的呢?查看Message类的源码,找到一个recycle方法,此方法又调用了recycleUnchecked方法,最终在recycleUnchecked方法里消息被回收添加到消息池中。

    // Handler.java
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

问题又来了,那recycle方法或recycleUnchecked方法什么被调用呢?全局搜索一下,在Looper类里找到loopOnce方法有调用Message的recycleUnchecked方法,代码如下:

    //Looper.java
    @SuppressWarnings("AndroidFrameworkBinderIdentity")
    private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {
        Message msg = me.mQueue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return false;
        }

       ......

        msg.recycleUnchecked();

        return true;
    }

什么是IdleHandler?

IdleHandler是一个接口,可用于执行一些在UI线程空闲时执行的任务。当Looper处于空闲状态时,系统会调用IdleHandler的回调方法,以执行一些额外的任务,如数据加载、后台计算等。

   // MessageQueue.java
    /**
     * Callback interface for discovering when a thread is going to block
     * waiting for more messages.
     */
    public static interface IdleHandler {
        /**
         * Called when the message queue has run out of messages and will now
         * wait for more.  Return true to keep your idle handler active, false
         * to have it removed.  This may be called if there are still messages
         * pending in the queue, but they are all scheduled to be dispatched
         * after the current time.
         */
        boolean queueIdle();
    }

如我们想在主界面显示完成后做一些事情,可以使用以下代码:

    Looper.myQueue().addIdleHandler(() -> {
         //加载数据等
         ......
         return false;
    });
上一篇 下一篇

猜你喜欢

热点阅读