Лучшее использование HandlerThread над другими подобными классами

Я пытаюсь понять лучший вариант использования использования HandlerThread.

согласно определению:

"удобный класс для запуска нового потока, который имеет петлителя. Затем looper можно использовать для создания классов обработчиков. Обратите внимание, что start() все еще должен быть вызван."

Я могу ошибаться, но аналогичной функциональности я могу достичь с помощью Thread, Looper и Handler. Итак, когда я должен использовать HandlerThread? Пример был бы очень полезен.

2 ответов


вот пример реальной жизни, где HandlerThread будет удобно. Когда вы регистрируетесь для кадров предварительного просмотра камеры, вы получаете их в onPreviewFrame() обратный. The документация поясняет, что этот обратный вызов вызывается в потоке событий open (int) был вызван из.

обычно это означает, что обратный вызов будет вызываться в основном потоке (UI). Таким образом, задача борьбы с огромными массивами пикселей может застрять, когда меню открыты, анимации анимируются, или даже если статистика в напечатанном на экране.

простое решение-создать new HandlerThread() и передать Camera.open() к этой теме (я сделал это через post(Runnable), вам не нужно осуществлять Handler.Callback).

обратите внимание, что вся другая работа с камерой может быть выполнена как обычно, вам не нужно делегировать Camera.startPreview() или Camera.setPreviewCallback() в HandlerThread. На всякий случай, я ... --27-->ждать для Camera.open(int) завершить перед I продолжить в основном потоке (или любом потоке, который использовался для вызова 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 () -- ждать() связь между потоками не требуется, если вы не имеете доступа mCamera в исходном коде сразу же после его открытия.

обновление: здесь тот же подход применяется акселерометр: датчик Акклерометра в отдельной резьбе


вот ссылка на исходный код HandlerThread и петлителя.

если вы посмотрите на двух вы увидите, что HandlerThread - Это именно то, что он говорит, что это - удобный способ начать Thread что есть Looper. Почему это существует? Потому что потоки, по умолчанию не имеют цикла сообщений. The HandlerThread Это просто простой способ создать тот, который делает. Не могли бы вы дублировать эту функцию с помощью Handler, Thread и Looper - судя по исходному коду - да.

An Executor разное. Ан Executor принимает представленные выполняемые задачи и-угадайте, что-выполняет их. Почему это необходимо? Это позволяет отделить выполнение задачи от ее фактического содержания. Когда ты это используешь? Допустим, у вас возникла ситуация, требующая выполнения нескольких задач одновременно. Вы можете выбрать, используя Executor, чтобы запустить их все в одном потоке, чтобы они были выполнены сериалы. Или вы можете использовать фиксированный пул потоков, чтобы некоторые, но не все запускались одновременно. В любом случае суть задачи - то есть то, что она на самом деле делает, - отделена от способа ее выполнения.