HandlerThread
を使用する最適な使用例を理解しようとしています。
定義に従って:
「ルーパーを持つ新しいスレッドを開始するための便利なクラス。ルーパーを使用してハンドラークラスを作成できます。start()を呼び出す必要があることに注意してください。」
間違っているかもしれませんが、Thread
、Looper
、およびHandler
を使用することで同様の機能を実現できます。それで、いつHandlerThread
を使うべきですか?例は本当に役立ちます。
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にアクセスしない場合、スレッド通信は不要です。
更新: ここでは、同じアプローチが加速度計に適用されます。 別のスレッドの加速度計センサー
HandlerThread および Looper のソースコードへのリンクを次に示します。
この2つを見ると、HandlerThread
がまさにその通りであることがわかります。これは、Thread
を持つLooper
を開始する便利な方法です。なぜこれが存在するのですか? スレッド、デフォルトではメッセージループがない であるため。 HandlerThread
は、作成する簡単な方法です。この関数をHandler
、Thread
、およびLooper
で複製できますか-ソースコードから判断すると、答えはイエスです。
Executor
は異なります。 Executor
は、サブミットされた実行可能なタスクを取得し、実行するものを推測します。なぜこれが必要なのですか? タスクの実行を実際の実体から切り離す が可能になります。これはいつ使用しますか?複数のタスクを同時に実行する必要がある状況があったとします。 Executor
を使用して、それらをすべて単一のスレッドで実行し、それらが連続して実行されるように選択できます。または、固定スレッドプールを使用して、すべてではなく一部を同時に実行することもできます。どちらの場合でも、タスクの実体、つまり実際に実行していることは、実行されている方法とは別のものです。