web-dev-qa-db-ja.com

他の同様のクラスに対するHandlerThreadの最適な使用

HandlerThreadを使用する最適な使用例を理解しようとしています。

定義に従って:

「ルーパーを持つ新しいスレッドを開始するための便利なクラス。ルーパーを使用してハンドラークラスを作成できます。start()を呼び出す必要があることに注意してください。」

間違っているかもしれませんが、ThreadLooper、およびHandlerを使用することで同様の機能を実現できます。それで、いつHandlerThreadを使うべきですか?例は本当に役立ちます。

67
Androidme

HandlerThread が便利になる実際の例を次に示します。カメラプレビューフレームに登録すると、onPreviewFrame()コールバックでそれらを受け取ります。 ドキュメント は、 このコールバックは、open(int)が呼び出されたイベントスレッドで呼び出されます

通常、これはコールバックがメイン(UI)スレッドで呼び出されることを意味します。したがって、メニューを開いたり、アニメーションをアニメートしたり、統計を画面に印刷したりすると、巨大なピクセル配列を処理するタスクがスタックする可能性があります。

簡単な解決策は、new HandlerThread()を作成し、Camera.open()をこのスレッドに委任することです(post(Runnable)を使用して行いました。Handler.Callbackを実装する必要はありません)。

カメラに関する他のすべての作業は通常どおりに実行できることに注意してください。Camera.startPreview()またはCamera.setPreviewCallback()をHandlerThreadに委任する必要はありません。安全のために、私は 待つ メインスレッド(または変更前にCamera.open(int)を呼び出すために使用されたスレッド)に進む前に、実際のCamera.open()が完了するため。


だから、コードから始めると

try {
    mCamera = Camera.open(1);
}
catch (RuntimeException e) {
    Log.e(LOG_TAG, "failed to open front camera");
}
// some code that uses mCamera immediately

最初にそれを抽出する そのまま プライベートメソッドに:

private void oldOpenCamera() {
    try {
        mCamera = Camera.open(1);
    }
    catch (RuntimeException e) {
        Log.e(LOG_TAG, "failed to open front camera");
    }
}

oldOpenCamera()を呼び出す代わりに、単にnewOpencamera()を使用します。

private void newOpenCamera() {
    if (mThread == null) {
        mThread = new CameraHandlerThread();
    }

    synchronized (mThread) {
        mThread.openCamera();
    }
}
private CameraHandlerThread mThread = null;
private static class CameraHandlerThread extends HandlerThread {
    Handler mHandler = null;

    CameraHandlerThread() {
        super("CameraHandlerThread");
        start();
        mHandler = new Handler(getLooper());
    }

    synchronized void notifyCameraOpened() {
        notify();
    }

    void openCamera() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                oldOpenCamera();
                notifyCameraOpened();
            }
        });
        try {
            wait();
        }
        catch (InterruptedException e) {
            Log.w(LOG_TAG, "wait was interrupted");
        }
    }
}

全体notify()-wait()inter-元のコードを開いた直後にmCameraにアクセスしない場合、スレッド通信は不要です。

更新: ここでは、同じアプローチが加速度計に適用されます。 別のスレッドの加速度計センサー

83
Alex Cohn

HandlerThread および Looper のソースコードへのリンクを次に示します。

この2つを見ると、HandlerThreadがまさにその通りであることがわかります。これは、Threadを持つLooperを開始する便利な方法です。なぜこれが存在するのですか? スレッド、デフォルトではメッセージループがない であるため。 HandlerThreadは、作成する簡単な方法です。この関数をHandlerThread、およびLooperで複製できますか-ソースコードから判断すると、答えはイエスです。

Executorは異なります。 Executorは、サブミットされた実行可能なタスクを取得し、実行するものを推測します。なぜこれが必要なのですか? タスクの実行を実際の実体から切り離す が可能になります。これはいつ使用しますか?複数のタスクを同時に実行する必要がある状況があったとします。 Executorを使用して、それらをすべて単一のスレッドで実行し、それらが連続して実行されるように選択できます。または、固定スレッドプールを使用して、すべてではなく一部を同時に実行することもできます。どちらの場合でも、タスクの実体、つまり実際に実行していることは、実行されている方法とは別のものです。

15
Rarw