最好使用HandlerThread而不是其他类似的类

时间:2013-08-09 15:10:01

标签: android android-handler

我试图了解使用HandlerThread的最佳用例。

根据定义:

  

“用于启动具有looper的新线程的Handy类。然后可以使用looper来创建处理程序类。请注意,仍然必须调用start()。”

我可能错了,但使用ThreadLooperHandler可以实现类似功能。那我什么时候应该使用HandlerThread?一个例子真的很有帮助。

2 个答案:

答案 0 :(得分:80)

以下是HandlerThread变得方便的真实例子。注册Camera预览帧时,您会在onPreviewFrame()回调中收到它们。 documentation解释了在从调用事件线程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");
        }
    }
}

请注意,如果您不访问 mCamera ,则无需进行整个 notify() - wait()线程间通信打开后立即在原始代码中。

更新:此处采用相同的方法加速度计:Acclerometer Sensor in Separate Thread

答案 1 :(得分:15)

以下是指向HandlerThreadLooper的源代码的链接。

如果你看两个,你会发现HandlerThread正是它所说的那样 - 一种方便的方式来启动Thread Looper。为什么会这样?因为threads, by default do not have a message loopHandlerThread只是创建一个的简单方法。您可以使用HandlerThreadLooper复制此功能 - 从源代码判断 - 答案是肯定的。

Executor不同。 Executor接受提交的可运行任务 - 猜猜是什么 - 执行它们。为什么这有必要?它允许你decouple the execution of the task from its actual substance。你什么时候用这个?假设您遇到需要同时执行多个任务的情况。您可以选择使用Executor在一个线程上运行它们,以便它们以串行方式执行。或者您可以使用固定的线程池,以便一些(但不是全部)同时运行。在任何一种情况下,任务的实质 - 即它实际上在做什么 - 都与它的执行方式分开。