Androidのメッセージハンドリング機構--Handler

1.なぜハンドラを使うのか?

サブスレッドがメインUIスレッドを変更することはできません、非同期メッセージ処理機構は、ハンドラがメインスレッドに、子スレッドから切り替えることによって完成し、要求データの完璧なソリューションの子スレッドは、メインスレッドは、UIの問題を更新します

2.Handler基本原則

メインスレッドがニュースの列(メッセージキュー)を維持し、子スレッドは、メッセージ(メッセージ)、ハンドラのメインスレッドでメッセージキュー(メッセージキュー)にメッセージを送信するために、ラウンドロビンがあるメインスレッドを作成します(ルーパー)、連続サイクルが列内のメッセージをチェックし、メッセージを取得するために、新しいメッセージがない、一度新しいメッセージを見つけ、ルーパーは、そうでない場合は待機状態にブロックされ、この時間はハンドラ自身を呼び出すオブジェクトハンドラに引き渡されますUIまたは他の操作を更新するコールバック関数DispatchMessageを(メッセージmsg)。
ハンドラ原則メカニズム

ソースコード分析の3.Handler組み合わせ

3.1メッセージ

メッセージ:メッセージ
データを搬送することができるスレッドデータ通信部との間には、必要な
メッセージプール(文字列定数プール、プールが接続され、スレッドプール) - Message.obtainを():オブジェクトを作成するために
カプセル化されたデータを
どの// ID識別パブリックINTを
公衆INT ARG1
ARG2公共int型
パブリックオブジェクトobj

メッセージメソッドMessage.obtainを(作成)

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

新しいオブジェクトではない新たな場合、オブジェクトのメッセージプール、メッセージプール50の最大数によって得られるメッセージ。

3.2ハンドラプロセッサ

メッセージハンドラプロセッサは、メッセージを送信し、除去作業が担当する
のsendMessage(メッセージmsg):インスタントメッセージの送信
メッセージの遅延送信:sendMessageDelayed(メッセージmsg、長い時間を )
メッセージを処理しますのhandleMessage(メッセージmsg)(コールバックを方法)
メッセージを除去するために処理されていない。removeMessages(INT何を)

メッセージキューにメッセージを送信するハンドラsendMessageメソッド、最終的な処理方法はenqueueMessageについて説明します

 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
 		//把当前Handler对象赋值给msg的成员变量target,保证了谁发送谁处理
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

Handlerオブジェクトのメソッドは、誰治療送信者を確認するために、ターゲットの変数MSGのメンバーに割り当てられています。最後に、処理のためのメッセージキューenqueueMessage()メソッドを与えられました。

3.3メッセージキューメッセージキュー

最後に何をするメッセージキュー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) {
            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();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                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.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

これは、プライオリティキューで注文した際に、メッセージのあるハンドラによって送信されたメッセージを格納するために使用されます。(処理されるべき時間を表す場合)

3.4ルーパーサーキュレータ

現在必要とされる処理メッセージ内を循環する責任メッセージキュー削除
に対応するハンドラを処理する
処理、将来の再利用のためのメッセージ・バッファ・プールにメッセージを

そして、質問が来ますか?ルーパーは、ニュースを取るとき?
それは?作成したときにルーパーがある
メッセージキューのフロントは、それが作成されたものを時間言いませんでしたが?

私たちは、まず、それはこの質問に答えるために前にアプリケーションが実行されている可能性がなぜ勃発したことを理解する必要がありますか?それは再びエントリの方法?
答えは、このクラスのActivityThreadの内部にあり、すべてのやったことを見

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

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        ...
        Looper.loop();
        ...
    }

主な方法はLooper.prepareMainLooper()、ゴー見て呼び出します

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

それをやった(false)を準備?

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

スレッド内のデータストレージ用sThreadLocal、sThreadLocal.set(新ルーパー(quitAllowed))作成したルーパーオブジェクトコンストラクタ行くのを見聖歌

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

ここで再び、私たちは、メッセージキューの位置に対応するルーパーは、相関していたと言うことですつまり、メッセージキューを作成しました。

ルーパーを作成した後、sMainLooper = myLooper()、彼らが何をしましたか?

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

今回は、メインスレッドは、このルーパーで作成されています。
mainメソッドに戻ると、最後に実行さLooper.loop();ときにそれを行うためのこの方法?質問で、それを見に行ってきました

    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        ...

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            ...
            try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }   
           ...
            msg.recycleUnchecked();
        }
    }

コードは、キーコードを抽出するために、全体を見てする必要はありませんが、長いです

最終ルーパー私= myLooper();作成されたメインルーパ糸の前に取得する
(;;){ため
のメッセージMSG = queue.next(); //メッセージ・キューからメッセージを取得する連続
IF(MSG == NULL){
//ループを終了するときのニュースはありません。
リターン;
}
...
試し{
//このメソッドは、ハンドラ処理にメッセージを配布するために使用され、ターゲットはそれに対処作られたユーザーを指定
msg.target.dispatchMessage(MSG)を;
}
}

これは、アプリケーションは常に開いて実行できる理由を説明され、死のサイクルで手動でプログラムを終了しない限り、何のメッセージは、プログラムを終了するには戻らないだろう、それ以外のメッセージは、読み取り、および利き出てきました

3.5 DispatchMessageをメッセージ配信処理

public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

これに対処するための3つの方法がありますが、

  1. handleCallback(MSG);
    コールバックメッセージが作成され、例えば、メッセージ自身によって処理:
	Handler handler = new Handler();
	handler.post(new Runnable() {
	    @Override
	    public void run() {
	    //UI操作
	    }
	});
  1. mCallback.handleMessage(MSG)
    ハンドラは、例えば、コールバック(内部インターフェース)、コールバックプロセス自体を作成しました。
   Handler.Callback callback = new Handler.Callback() {
       @Override
       public boolean handleMessage(Message msg) {
       		//UI操作
           return false;
       }
   };
   Handler handler = new Handler(callback);
   //子线程发送消息
   handler.sendMessage(msg);
  1. handleMessage(MSG)例:
     Handler handler = new Handler(){
          @Override
          public void handleMessage(Message msg) {
              //UI操作
          }
      };
	  //子线程发消息
	  handler.sendMessage(message);

そして、回路図を添付
ハンドラ原理
参考のために開いているいくつかの問題を残しましたか?
postメソッドとのsendMessage 1.Handlerがある方法の違いは何ですか?
2.ハンドラあなたは子スレッドで作成することができますか?どのように作成するには?
3. Aスレッドが複数のハンドラ、ルーパー、MessegeQueueそれを持つことができますか?

公開された28元の記事 ウォンの賞賛1 ビュー527

おすすめ

転載: blog.csdn.net/qq_40575302/article/details/104535997