Ответ 1
Вот пример реальной жизни, когда 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
сначала извлеките его as is в частный метод:
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() не требуется, если вы не получаете доступ к mCamera в исходном коде сразу после его открытия.
Обновление: Здесь тот же подход применяется к акселерометру: Датчик акселерометра в отдельной теме