1. View の読み込みと描画のプロセスには、コレオグラファー クラス mChoreographer があります。
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
同期バリア メッセージを MessageQueue に挿入します。msg.target==null メッセージ、戻り値 mTraversalBarrier は int トークン値です。
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; //向消息队列插入一个同步屏障的消息。msg.target==null的消息 mTraversalBarrier = mHandler.getLooper().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); } }
mChoreographer.postCallback() メソッドは、mTraversalRunnable のコードを実行します。
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
これにより、上記で生成されたトークン値に基づいて、MessageQueue 内の同期バリア メッセージが削除されます。
final TraversalRunnable mTraversalRunnable = new TraversalRunnable(); final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; //移除同步屏障消息 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); //在这个方法中会调用 measure layout draw,view的绘制绘制流程的方法 performTraversals(); } }
このコード行 mHandler.getLooper().postSyncBarrier() を見て、システムがそれをどのように処理するかを見てみましょう。
ハンドラーが設定されていないメッセージを取得しました。
int enqueueSyncBarrier(long when) { // Enqueue a new sync barrier token. // We don't need to wake the queue because the purpose of a barrier is to stall it. synchronized (this) { final int token = mNextBarrierToken++; // 这个msg.target没有被赋值 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; } }
通常、メッセージはハンドラーを通じて送信され、ハンドラーを空にすることはできません。
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } ........... }
なぜシステムは空のハンドラーを含むメッセージを送信するのでしょうか?
まず、同期バリア メッセージを送信した後に mChoreographer が何をしたかを見てみましょう。
別の非同期メッセージが送信されました: msg.setAsynchronous(true)。このメッセージのハンドラーは null ではありません。
private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) { synchronized (mLock) { final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); if (dueTime <= now) { scheduleFrameLocked(now); } else { Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); msg.arg1 = callbackType; //将消息设置为异步消息 msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, dueTime); } } }
次に、MessageQueue がメッセージを削除する方法と、この同期バリア メッセージを処理する方法を見てみましょう。
Message next() { synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; //如果msg.target==null说明我们已经向消息队里中插入了一条屏障消息。 //此时会进入到这个循环中,找到msg.isAsynchronous==true的异步消息。 //通常我们发送的都是同步消息isAsynchronous = false的,并且msg.target不能为null的。 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());//msg.isAsynchronous==true时结束循环,说明找到了这个异步消息。 } 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 (false) Log.v("MessageQueue", "Returning message: " + msg); return msg; } } else {//没有找到的话则进入休眠直到下一次被唤醒 // No more messages. nextPollTimeoutMillis = -1; } } }
キャンセルする場合は、まず msg.target が null かどうかを確認し、次に while ループを通過して msg.isAsynchronous() == true というメッセージを見つけます。それが上記で送信された非同期メッセージです。通常、送信するメッセージは同期メッセージであるため、msg.setAsynchronous(true); は設定されません。
システムの目的は、この非同期メッセージを最初に処理することです。すべての同期メッセージはバリアと同様に後ろに配置されるため、このような操作は同期バリアと呼ばれ、同期バリア メッセージの処理の方が優先されます。
コレオグラファー クラス mChoreographer は画面のレンダリングを担当するため、インターフェイスの更新頻度を確保するために最下層からの信号をタイムリーに処理する必要があります。
以上がJava ハンドラー同期バリアのサンプル コード分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。