HandlerThread
的最佳用例。 按照定义:
“方便的类,用于启动具有循环程序的新线程。然后,可以使用循环程序创建处理程序类。请注意, start()必须仍然被调用。“
我可能是错的,但是使用
Thread
,Looper
和Handler
可以实现类似的功能。那么我什么时候应该使用HandlerThread
?一个例子真的很有帮助。#1 楼
这是一个实际的示例,其中HandlerThread变得很方便。注册摄像机预览框时,您会在onPreviewFrame()
回调中收到它们。文档解释说,此回调是在从其调用open(int)事件线程上调用的。通常,这意味着该回调将在主(UI)线程上调用。因此,打开菜单,动画制作动画或即使屏幕上打印了统计信息时,处理巨大像素阵列的任务也可能卡住。简单的解决方案是创建一个
new HandlerThread()
和将Camera.open()
委托给该线程(我是通过post(Runnable)
完成的,您无需实现Handler.Callback
)。请注意,使用Camera进行的所有其他工作都可以照常进行,您不必将
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()线程间通信mCamera打开后立即在原始代码中显示。
更新:此处对加速度计采用了相同的方法:加速度计传感器位于单独的线程中
评论
那你要在哪里合上相机呢?
–马特西亚斯
2014年2月24日在8:13
@Matthias:这是一个很好的问题。如果您的用例允许这样做,请在Activity.onPause()中释放摄像机-首先,因为根据Activity生命周期,这是保证您的活动从系统接收到的唯一回调。但是在某些情况下,可以在onPause()之后使用相机。在这种情况下,您只需要几个位置即可在不同情况下保持优雅。
– Alex Cohn
2014年2月24日13:56
)}关闭新的Runnable应该是})
–丰富
2014年3月23日在7:17
@Praveen当然,在这种情况下,“静态”没有什么神圣的
– Alex Cohn
2014年12月22日19:17
@Praveen:这是您可以在覆盖notify()时执行的操作
– Alex Cohn
2014-12-26 21:05
#2 楼
这是HandlerThread和Looper源代码的链接。如果同时查看两者,您会发现
HandlerThread
正是它所说的-启动具有Thread
的Looper
的便捷方法。为什么会存在?因为线程默认情况下没有消息循环。 HandlerThread
只是创建一个简单的方法。您能否使用Handler
,Thread
和Looper
复制此功能-从源代码来看-答案是肯定的。 Executor
不同。 Executor
接受已提交的可运行任务,然后猜猜是什么,然后执行它们。为什么这是必要的?它使您可以将任务的执行与其实际内容脱钩。你什么时候用这个?假设您遇到需要同时执行多个任务的情况。您可以选择使用Executor
在单个线程上全部运行它们,以便按顺序执行它们。或者,您可以使用固定线程池,以使某些(但不是全部)同时运行。在这两种情况下,任务的实质(即任务的实际执行方式)与执行方式是分开的。 评论
我认为您的区分是不准确的。您也可以通过Handler.postRunnable提交要执行的任务。实际上,您可以通过仅更改ThreadFactory和Submit()方法来创建仅使用HandlerThreads的ExecutorService。借助HandlerThreads,跨线程通信变得更加容易,而不是任务提交。
– Delyan
13年8月10日在13:58
我猜不清楚。我并不是要暗示执行者使任务执行更加容易。而是将执行程序的目的设计为仅处理那些任务的执行。 HandlerThread的用途不同。稍后再编辑。
–Rarw
13年8月10日在14:27
评论
我从未使用过HandlerThread,但也许这篇文章会有所帮助-stackoverflow.com/questions/7462098 / ...@TalKanel:感谢您的答复。我已经检查了这篇文章,但它谈到了Executor相对于HandlerThread的好处,我完全同意。我的问题更像是使用HandlerThread的最佳用例是什么
该帖子也解决了这个问题。执行程序更灵活,因为他们可以管理线程池。多线程-您需要使用执行程序。单线程-您可以使用HandlerThread。不确定是否重要,因为执行官可以同时处理这两种情况。据我了解,HandlerThread仅允许您在后台线程上创建处理程序-可以通过其他方式完成此操作。
在这里查看我的评论-stackoverflow.com/questions/17897536/how-to-handle-tcp-data /...。通常,我更喜欢HandlerThreads,因为它通过消息实现了超级简单的同步。也就是说,这也可能是瓶颈。此外,没有什么阻止您将ExecutorService与HandlerThreads一起使用。我以前写过一篇,并不难。
@Rarw:这实际上是我的问题,如果我们可以通过其他方式来做事情,那么创建另一个类需要做什么。我确信在特殊情况下有一些好处,我需要知道。