我们如何从执行者那里得到弯针?

时间:2020-03-25 23:55:55

标签: android

Google关于绑定服务的文档正在推广using a Messenger in lieu of your own custom binding for IPC。因此,我尝试尝试a particular experiment that I am running

但是,Messenger需要一个Handler。如今,Handler需要一个Looper,在这种情况下,无论如何我都可能想要一个作为后台线程(与Looper.getMainLooper()相对)。我唯一知道的另一种Looperrun()HandlerThread并从中获得Looper

the deprecated non-Looper forms of the Handler constructor的文档包括:

在Handler构造过程中过分选择Looper可能会导致以下错误:操作无提示地丢失操作(如果Handler不期望新任务并退出),崩溃(如果有时在未激活Looper的线程上创建了处理程序),或竞争条件,处理程序与之关联的线程不是作者预期的。 相反,请使用Executor或使用Looper#getMainLooper,View#getHandler或类似工具显式指定Looper。

(添加了重点)

这是措辞奇怪的文档,还是存在使LooperHandler与我似乎找不到的Executor绑定的秘诀?

2 个答案:

答案 0 :(得分:1)

我认为他们的意思是建议使用Executor而不是Handler。我不知道有Executor支持的任何Looper实现。

使用Handler或类似的方法代替Executor,而使用Looper或明确指定Looper#getMainLooper。 >

仅在需要运行View#getHandler时有用。例如,CameraManager.openCamera()方法在API级别28处有重载。

此方法的行为与Runable的行为匹配,不同之处在于它使用openCamera(java.lang.String, StateCallback, android.os.Handler)作为参数而不是Executor

如果您需要Handler,则始终必须提供Messenger支持的HanlderLooperLooper.getMainLooper()已解决或通过Looper.myLooper()

或者,您可以创建一个HandlerThread并在其上运行loop()。但这基本上就是Looper所做的。

答案 1 :(得分:1)

更新:TL; DR

// Check if this thread already has prepared a looper
if (Looper.myLooper() == null) {
    Looper.prepare()
}
val threadHandler = Handler(Looper.myLooper())
val messenger = Messenger(threadHandler)
messenger.send(...)

长期回答

如果您想进一步了解正在发生的事情以及每段代码在哪个线程中运行:

// Check if this thread already has prepared a looper
// Running on Original Thread
if (Looper.myLooper() == null) {
    Looper.prepare()
}
// Save thread's Looper (1)
// Running on Original Thread
val threadLooper = Looper.myLooper()
Handler(Looper.getMainLooper()).post {
    // Do some UI stuff, for instance, show a dialog
    // Running on UI Thread
    AlertDialog
        .Builder(context)
        .setTitle("Dialog title")
        .setMessage("Dialog message")
        .setNegativeButton("Cancel") { _: DialogInterface, _: Int ->
            // Use thread's Looper from (1) to notify the original thread
            // Running on UI Thread
            Handler(threadLooper).post {
                // Running on Original Thread
                callback?.onCancel()
            }
        }
        .setPositiveButton("Retry") { _: DialogInterface, _: Int ->
            // Use thread's Looper from (1) to notify the original thread
            // Running on UI Thread
            Handler(threadLooper).post {
                // Running on Original Thread
                callback?.onRetry()
            }
        }
        .show()
}
// Call loop() to start the thread's loop
// Running on Original Thread
Looper.loop()