关于Handler我们应该知道的知识

Handler可以帮助我们在特定的线程执行任务。我们也可以用Handler计划一个任务在未来某个时间点执行。Handler会将我们给它的任务在特定的线程里进行排队执行。如果我们想在某个线程做些什么任务,我们可以指定Handler的Looper,然后Handler就会将这个任务添加到Looper对应的消息队列(message queue)。

        val handler = Handler(Looper.getMainLooper())
        val runnable = Runnable {
    
    
            println("Hello world")
        }
        handler.postDelayed(runnable,3_000L)

创建Looper

我们在某个线程里调用Looper.prepare(),就会给这个线程创建一个Message Queue

Looper.getMainLooper()的有关的代码:
这是应用在启动时,调用的main函数。main函数写在哪里是无所谓的,在计算机操作系统里已约定好程序的入口是main,所以你也会看到它是static的。android的应用程序的main函数都写在ActivityThread.java这个文件里。下面是启用启动时准备主线程使用的Looper:

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

prepareMainLooper()函数:
看到未!它调用了prepare()函数。为当前线程准备Looper

public static void prepareMainLooper() {
    
    
        prepare(false);
        synchronized (Looper.class) {
    
    
            if (sMainLooper != null) {
    
    
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

prepare()函数:
为当前线程(主线程)创建一个Looper,因为是主线程,所以quitAllowed要传false。否则Message Queue里的消息就会有被销毁的风险。

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

创建Looper的同时会当前线程创建一个MessageQueue:

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

创建好的Looper会被保存起来:

    public void set(T value) {
    
    
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

prepare()函数调用完成后Looper创建工作就完成了,调用myLooper()就是去将这个Looper拿回来赋给sMainLooper,Looper.getMainLooper()拿到的就是这个值:

    public static @Nullable Looper myLooper() {
    
    
        return sThreadLocal.get();
    }
 public static @Nullable Looper myLooper() {
    
    
        return sThreadLocal.get();
    }
public T get() {
    
    
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
    
    
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
    
    
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

到此应用启动后马上为主线程创建好了一个Looper了,通过Looper.getMainLooper()就可以拿到这个主线程的Looper。

public static Looper getMainLooper() {
    
    
        synchronized (Looper.class) {
    
    
            return sMainLooper;
        }
    }

顺便提一下,Looper创建出来的MessageQueue是一个链表,它的元素是Message:

public final class MessageQueue {
    
    
    @UnsupportedAppUsage
    Message mMessages;
    
    ...
	@UnsupportedAppUsage
	Message next() {
    
    
        ...
        for (;;) {
    
    
            ...
            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) {
    
    
                        ...
                    } else {
    
    
                        // Got a message.
                        ...
                        if (prevMsg != null) {
    
    
                            prevMsg.next = msg.next;
                        } else {
    
    
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        ...
                        msg.markInUse();
                        return msg;
                    }
                } 
				...
            }
        }
    }
}

Handler与Looper的关系

我们拿到了主线程的Looper传给Handler有什么用呢?首先,Handler是android.os包里一个普通的类。
我们创建一个Handler实例,这个实例引用着主线程的Looper:

val handler = Handler(Looper.getMainLooper())
public Handler(@NonNull Looper looper) {
    
    
    this(looper, null, false);
}

通过对主线程Looper的引用,Handler也引用着主线程Looper的MessageQueue:

    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
    
    
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

Handler怎么使用Looper呢?我以上面为例来说明:

handler.postDelayed(runnable,3_000L)
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
    
    
   return sendMessageDelayed(getPostMessage(r), delayMillis);
}

getPostMessage()将我们的任务(任务都是用Runnable来写的)生成一个Message:

private static Message getPostMessage(Runnable r) {
    
    
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

Message.obtain()会先偿试从消息池找一个,如没有就创建一个新的。消息池是一个链表:

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

我们的任务是放在Message的callback字段上的,而Message的target将要放的是我们的Handler对象,请往下继续阅读:

Message{
    
    
	...
    @UnsupportedAppUsage
    /*package*/ Runnable callback;
        @UnsupportedAppUsage
    /*package*/ Handler target;
    ...
}

sendMessageAtTime()函数,这是一个过渡,做些准备:

    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    
    
        if (delayMillis < 0) {
    
    
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

Handler拿出Looper的MessageQueue,准备做最后的消息入队操作:

    public boolean sendMessageAtTime(@NonNull 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);
    }

Handler对象将自己的引用给了创建出来的Message对象的target字段,然后,通过Looper对象的MessageQueue对象将Message送入队列:

    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
    
    
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
    
    
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

至此Handler已完成了它的工作了,那么Looper的MessageQueue里的Message消息什么时候会被取出来操作呢?

Message的执行

main函数最后面有这么一行Looper.loop();,使android应用程序不会退出,因此它会一直循环下去。否则main函数就会被结束。

    public static void main(String[] args) {
    
    
        ...

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

loop()函数会拿出当前线程的Looper,比如当前线程是主线程,那么myLooper()拿回来的就是主线程的Looper()

public static void loop() {
    
    
        final Looper me = myLooper();
        ...
        for (;;) {
    
    
            if (!loopOnce(me, ident, thresholdOverride)) {
    
    
                return;
            }
        }
    }

从当前线程的Looper的MessageQueue取出一个Message,然后把Message给Message的target字段记录的Handler对象处理:

    private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {
    
    
        Message msg = me.mQueue.next(); // might block
        ...
        try {
    
    
            msg.target.dispatchMessage(msg);
          ...  
        } 
        
        ...

        return true;
    }

Handler的dispatchMessage()方法,如果callback不是null就是去执行,callback记录的是我们的任务:

 public void dispatchMessage(@NonNull Message msg) {
    
    
        if (msg.callback != null) {
    
    
            handleCallback(msg);
        } else {
    
    
            if (mCallback != null) {
    
    
                if (mCallback.handleMessage(msg)) {
    
    
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    private static void handleCallback(Message message) {
    
    
        message.callback.run();
    }

如果msg.callback是null,且在创建Handler对象时有传个callback的话,就会先调用这个callback再调用handleMessage()方法:

public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async)
    public void handleMessage(@NonNull Message msg) {
    
    
    }

handleMessage()是一个空方法,所在此方面的实践,往往需要我们重写它,例子:

val handler = object: Handler(Looper.getMainLooper()){
    
    
            override fun handleMessage(msg: Message) {
    
    
                println("Hello world")
            }
        }
        
val msg = Message.obtain()
handler.sendMessage(msg)

到此我们知道,任务在哪个线程执行的关键就是prepare()在哪里被执行,也就是为哪个线程创建Looper,发送到这个Looper的任务就会在相应的线程里执行。

runOnUiThread到底做了什么?

class Activity  ... {
    
    
	...
	 final Handler mHandler = new Handler();
	 ...
    public final void runOnUiThread(Runnable action) {
    
    
        if (Thread.currentThread() != mUiThread) {
    
    
            mHandler.post(action);
        } else {
    
    
            action.run();
        }
    }
}
    public final boolean post(@NonNull Runnable r) {
    
    
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

Activity实例创建时,也会构造一个Handler实例,runOnUiThread()就是利用这个Handler实例向主线程的Looper发现任务。

Handler的知识大体是这样,更多其他涉及的知识,我们以后再分享啦。

猜你喜欢

转载自blog.csdn.net/weixin_40763897/article/details/128962456