Лучшее использование 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
, чтобы запустить их все в одном потоке, чтобы они были выполнены сериалы. Или вы можете использовать фиксированный пул потоков, чтобы некоторые, но не все запускались одновременно. В любом случае суть задачи - то есть то, что она на самом деле делает, - отделена от способа ее выполнения.