5

問題は、 Thread にLooperにmHandlerを使用するように指示する場所です。

ありがとうございました。以下のコードを使用しています。

class LooperThread extends Thread {
    public Handler mHandler;
    public void run() {
      Looper.prepare();

      mHandler = new Handler() {
          public void handleMessage(Message msg) {
              // process incoming messages here
          }
      };

      Looper.loop();
    }
}
4

3 に答える 3

5

問題は、ルーパーに mHandler を使用するようにスレッドに指示する場所です。

システム (フレームワーク) が自動的に行うため、明示的に伝える必要はありません。をインスタンス化するHandlerと、現在の のメッセージ キューへのアクセスが自動的に取得されますThread。あなたのコメントを引用:

システムはどのようにして にメッセージを送信することを認識していますmHandler Handlerか?

以下に詳しく説明します。

android.os.HandlerこれはAndroidのコンストラクタです。

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;

ご覧のとおり、最初にLooper現在の の を取得しますThread。のソースコードLooper.myLooper()は次のとおりです。

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

スレッド ローカル ストレージから取得します。後で、Messagethis を使用して を送信するとHandler、 はHandler実際に自分自身を の受信者Messageとして設定します。これにより、 は、が到着したときにLooperを発送する場所を知ることができます。Message詳細に:

を呼び出すとmHandler.sendMessage()、最終的にこのコードが実行されます (他の多くのコード行の中で):

    MessageQueue queue = mQueue;
    boolean sent = false;
    if (queue != null) {
        msg.target = this; // msg is your Message instance
        sent = queue.enqueueMessage(msg, uptimeMillis);
    }

ご覧のとおり、Handlerインスタンスを のターゲットとして設定しますMessage。そのため、後でMessageがディスパッチされると、 がHandlerターゲットとして含まれます。これにより、ウィルは、ディスパッチ先Looperを知ることができます。Handler詳細には、 を呼び出すと、キュー内のインスタンスLooper.loop()ごとに次の処理が行われます。Message

msg.target.dispatchMessage(msg);

dispatchMessage()コードは次のとおりです。

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

最後の handleMessage(msg)呼び出しに注意してください。これはまさにあなたのhandleMessage(msg)オーバーライドです!

于 2012-12-25T13:39:53.100 に答える
5

理解を深めるために、法線を作成し、そのスレッドのメソッドで をThread作成してみてください。あなたはことわざを得るでしょう:Handlerrun()RuntimeException

呼び出されていないスレッド内にハンドラーを作成できません Looper.prepare()

run()を作成する前にメソッドで Looper.prepare() を呼び出すと、呼び出し元のスレッドに関連付けられHandlerた新しいLooperオブジェクトが作成されます。混乱の原因は、 Looper.prepare() がas 引数を取らないことです。現在実行中のスレッドのを内部的に取得する静的メソッドであるため、その必要はありません。任意の に関連付けることができるのは最大 1 つです。ThreadThreadLocalLooperThread

ここで、 を呼び出すと、を内部的に呼び出すことによってnew Handler()、新しいHandlerオブジェクトがLooper現在の の に関連付けられます。同じスレッド内に独自のコールバックを持つものを複数作成できます。すべてのハンドラは、同じ のメッセージ キューからメッセージを取得します。ThreadLooper.myLooper()HandlerLooper

于 2012-12-25T13:02:16.420 に答える
3

あなたは何も言わない。Handlerドキュメントから:

各 Handler インスタンスは、単一のスレッドとそのスレッドのメッセージ キューに関連付けられています。新しいハンドラーを作成すると、それを作成しているスレッドのスレッド/メッセージ キューにバインドされます。その時点から、メッセージとランナブルがそのメッセージ キューに配信され、メッセージ キューから出てくると実行されます。 .

ハンドラーは、スレッドのメッセージ キューに自動的にバインドされます。コールバックを実装するだけで、システムがすべてを処理します。つまり、メッセージのディスパッチと処理です。実際、Looper.prepare()Looper.loop()と のような 2 つの静的メソッドを使用すると、物事を自動的に推論すると、パターンが黒魔術のように感じられることに同意します :)

于 2012-12-25T12:22:38.800 に答える