HandlerThreadソースコード分析

4299 ワード

HanderThreadというクラスに注目していなかったのは、ソースコードをひっくり返して発見するのが簡単でした.これは実はThreadサブクラスで、Looperを作成してLooperループを開きました.私たちは以前、Handlerを使ってUIスレッドの中でnewのHandlerを行ってサブスレッドの中でsendMessageを行くことに慣れていました.これにより、サブスレッドが時間のかかる操作を実行し、UIスレッドの中で新しいUIを実行することができます.しかし、サブスレッドで時間のかかる操作をしてサブスレッドで新しいUIと話す必要がある場合があります.不可能だと言わないでください.Surface View?これで私たちのLooperはUIスレッドでMessageメッセージを受信できません.この操作には一般的にいくつかの方法がある.1.サブスレッドでwhileまたはforサイクルを用いて時間と新しい操作を繰り返す.サブスレッドにLooperを作成し、Looper pre()とloop()を呼び出してメッセージをループおよび送信します.
第1の操作はまず探究しないで、HandlerThreadは第2の方式に対して簡単なパッケージで、実現をもっと容易にします
使い方を見てみましょう
        HandlerThread handlerThread=new HandlerThread("new_thread1");
        handlerThread.start();
        Handler handler=new Handler(handlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };

不思議なほど簡単な感じがしますが、これだけのコードでいいのではないでしょうか.Handlerがプライマリスレッドからnewが出てきても、メッセージを処理するのは私たちが作成したnew_です.thread 1というサブスレッドで実行して、もしあなたも好奇心を感じたら、私たちはソースコードを分析して、分析する前に、まずHandler Looper Messageの間の知識を思い出して、簡単な思い出の下で、HandlerがUIスレッドの中で消息を処理できるのはUIスレッドの中でnewが出てきたからだと知っています.どのサブスレッドでhandlerを呼び出してMessageを送信しても、UIスレッドのLooper内のMessageQueueに送信されます.このLooperは、UIスレッドでloop()を呼び出してキューメッセージをブロックするUIスレッドのLooper内のMessageQueueに送信されます.メッセージを受け取ってメッセージのhandlerのdispatchMessage()を呼び出してメッセージを処理するのでuiスレッドで必ず発生します
  public Handler(Looper looper) {
        this(looper, null, false);
    }
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

一方、HandlerにはLooperパラメータを受信する構造があり、最終的には3つのパラメータ構造が呼び出されます.この構造ではLooperをメンバー変数に付与します.HandlerThreadを操作すると、そのLooperを取得してHandlerメンバー変数に付与します.では、そのLooperはどこで作成されたのでしょうか.実際には、書き換えたrun()メソッドでは信じられません.
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

見たでしょう、その中にonLooperPrepared()があります.メソッドは空の実装メソッドloop()メソッド呼び出しの前にいくつかの準備作業を行うことができますが、start()呼び出しを開始して新しいスレッドを開きrun()メソッドでLooperを作成したが、スレッド間の実行順序が不確定であるため、いくつかの知識点に注意してください.したがって,getLooper()でこのオブジェクトを取得するには,等子スレッド内のLooperオブジェクトが完全に作成されている必要があるため,getLooper()メソッドで空wait()状態を判別する.
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

ロoperとしてprepare()呼び出し完了Looperオブジェクト作成完了呼び出しnotifyAll前のwait()のスレッドが起動しました