日本免费全黄少妇一区二区三区-高清无码一区二区三区四区-欧美中文字幕日韩在线观看-国产福利诱惑在线网站-国产中文字幕一区在线-亚洲欧美精品日韩一区-久久国产精品国产精品国产-国产精久久久久久一区二区三区-欧美亚洲国产精品久久久久

android延遲執(zhí)行優(yōu)化 安卓開機自啟動管理

首先,需要明確一點,Handler 延時消息機制不是延時發(fā)送消息,而是延時去處理消息;舉個例子,如下:
handler.postDelayed(() ->{Log.e("zjt", "delay runnable");}, 3_000);上面的 Handler 不是延時3秒后再發(fā)送消息,而是將消息插入消息隊列后等3秒后再去處理 。
postDelayed 的方法如下:
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {return sendMessageDelayed(getPostMessage(r), delayMillis);}其中的 getPostMessage 就是將 post 的 runnable 包裝成 Message,如下:
private static Message getPostMessage(Runnable r) {// 使用 Message.obtain() 避免重復(fù)創(chuàng)建實例對象,達到節(jié)約內(nèi)存的目的Message m = Message.obtain();m.callback = r;return m;}sendMessageDelayed 方法如下:
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {if (delayMillis < 0) {delayMillis = 0;}// 延時的時間是手機的開機時間(不包括手機休眠時間)+ 需要延時的時間return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}sendMessageAtTime 如下:
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);}這里面的代碼很好理解,就不說了,看看 enqueueMessage:
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {msg.target = this; // 設(shè)置 msg 的 target 為Handlermsg.workSourceUid = ThreadLocalWorkSource.getUid();// 異步消息,這個需要配合同步屏障來使用,可以看我之前的文章,這里不贅述if (mAsynchronous) {msg.setAsynchronous(true);}// 插入到 MessageQueue 中return queue.enqueueMessage(msg, uptimeMillis);}MessageQueue 的 enqueueMessage 的方法如下:
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) {// 判斷發(fā)送消息的進程是否還活著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(); // 標(biāo)記消息正在使用msg.when = when;Message p = mMessages; // 獲取表頭消息boolean needWake;// 如果隊列中沒有消息 或者 消息為即時消息 或者 表頭消息時間大于當(dāng)前消息的延時時間if (p == null || when == 0 || when < p.when) {// New head, wake up the event queue if blocked.msg.next = p;mMessages = msg;// 表示要喚醒 Hander 對應(yīng)的線程,這個后面解釋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.nextprev.next = msg;}// 喚醒Handler對應(yīng)的線程if (needWake) {nativeWake(mPtr);}}return true;}舉個例子,假設(shè)我們消息隊列是空的,然后我發(fā)送一個延時10s的延時消息,那么會直接把消息存入消息隊列 。
從消息隊列中獲取消息是 通過 Looper.loop() 來調(diào)用 MessageQueue 的 next()方法,next()的主要代碼如下:
Message next() {// Return here if the message loop has already quit and been disposed.// This can happen if the application tries to restart a looper after quit// which is not supported.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();}// 表示要休眠多長時間,功能類似于wait(time)// -1表示一直休眠,// 等于0時,不堵塞// 當(dāng)有新的消息來時,如果handler對應(yīng)的線程是阻塞的,那么會喚醒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) {// 計算延時消息的剩余時間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 {// No more messages.nextPollTimeoutMillis = -1;}.......// 判斷是否有 idle 任務(wù),即主線程空閑時需要執(zhí)行的任務(wù),這個下面說if (pendingIdleHandlerCount <= 0) {// 這里表示所有到時間的消息都執(zhí)行完了,剩下的如果有消息一定是延時且時間還沒到的消息;// 剛上面的 enqueueMessage 就是根據(jù)這個變量來判斷是否要喚醒handler對應(yīng)的線程mBlocked = true;continue;}......} }

推薦閱讀