如何将“goAsync”用于广播接收器?

Posted

技术标签:

【中文标题】如何将“goAsync”用于广播接收器?【英文标题】:How to use "goAsync" for broadcastReceiver? 【发布时间】:2014-05-09 14:08:58 【问题描述】:

背景

从 Honeycomb (API 11) 开始,android 具有允许广播接收器以异步方式运行的功能,在假定它可以终止其进程之前提供大约 10 秒,使用称为“goAsync”的方法:

这可以由 onReceive(Context, Intent) 中的应用程序调用以 允许它在从那个返回后保持广播活动 功能。这并没有改变相对的期望 响应广播(在 10 秒内完成),但允许 将与之相关的工作转移到另一个线程的实现 以避免由于磁盘 IO 而导致主 UI 线程出现故障。

问题

我搜索了很多地方,没有找到任何使用方法的示例或教程。

不仅如此,该方法还返回一个 PendingIntent 实例,我不确定如何处理它:

返回一个表示结果的 BroadcastReceiver.PendingResult 活跃的广播。 BroadcastRecord 本身不再活跃; 所有数据和其他交互都必须经过 BroadcastReceiver.PendingResult API。 PendingResult.finish() 广播处理完成后必须调用方法。

问题

您如何使用这种方法?

它返回的PendingIntent是什么,我该怎么处理?

【问题讨论】:

【参考方案1】:

你可以找到简短的解释here。

如果您想将BroadcastReceiveronReceive() 方法内部的处理移交给另一个线程,请使用goAsync()。然后可以在那里完成onReceive() 方法。 PendingResult 被传递给新线程,您必须调用PendingResult.finish() 来实际通知系统此接收器可以回收。

例如:

final PendingResult result = goAsync();
Thread thread = new Thread() 
   public void run() 
      int i;
      // Do processing
      result.setResultCode(i);
      result.finish();
   
;
thread.start();

【讨论】:

从onReceive方法返回的总时间为10秒。这意味着您的线程最多可以运行 10 秒减去您在启动线程之前在 onReceive 方法中花费的时间。没有尝试过代码,因为它在那里 setResult 不是必需的,它仅用于在有序广播期间在接收器之间传递数据。你可以忽略它。 我不明白 setResultCode 的用途以及如何使用它。你将如何传递它?另外,您是否尝试过此代码? 一个有序的广播按顺序通过每个注册的广播接收器。顺序由意图过滤器的优先级属性定义。然后,每个接收器都可以使用 setResult() 之类的方法将数据传递给下一个接收器,甚至完全停止广播。行动。 ACTION_NEW_OUTGOING_CALL 是一个有序广播。您可以使用 setResult 修改额外的 EXTRA_PHONE_NUMBER,这将更改将要拨打的电话号码。 setResult 方法接受一个 int、String 和一个 Bundle。如果是电话号码,您可以通过这种方式传递包含电话号码的捆绑包。不过,这与原始问题的主题非常偏离。问题是关于如何使用 goAsync,而不是关于 BroadcastReceiver 一般如何工作。如果该部分已回答,请标记为已解决。【参考方案2】:

kotlin中你可以在BroadcastReceiver上写一个扩展函数:

/**
 * Run work asynchronously from a [BroadcastReceiver].
 */
fun BroadcastReceiver.goAsync(
    coroutineScope: CoroutineScope,
    dispatcher: CoroutineDispatcher,
    block: suspend () -> Unit
) 
    val pendingResult = goAsync()
    coroutineScope.launch(dispatcher) 
        block()
        pendingResult.finish()
    

在您的广播接收器中之后,您可以执行以下操作:

class AlarmBroadcastReceiver : BroadcastReceiver() 

    override fun onReceive(context: Context, intent: Intent) 
        // Code here runs on the main thread

        goAsync(GlobalScope, Dispatchers.Default) 
            // The code here will run on the background by the default dispatcher on the global scope
            // If your code here touches the IO, then you can use Dispatchers.IO instead
        
    

【讨论】:

为什么需要参数?它总是相同的参数。相反,它应该只有在那里做什么的参数。另外,我认为您不应该在这里使用协程。如果它的线程池中有一些线程正在被使用,它会先等待它们完成。 对于参数,也许你有一个托管协程范围,你想在这种情况下使用。不推荐使用全局范围,因为它不支持结构化并发。使用协程简化了代码,您可以立即执行代码,而无需使用特定的调度程序等待。 原来你写了代码,现在又说不推荐使用? 我建议将块包装在 try finally 中,以确保最后始终调用 finish() 只是给未来的谷歌人的一个提示,Ian Lake 在 Muzei 应用程序中将其与 GlobalScope 一起使用,所以我认为它可能没问题 github.com/muzei/muzei/blob/…

以上是关于如何将“goAsync”用于广播接收器?的主要内容,如果未能解决你的问题,请参考以下文章

如何将结果数据从广播接收器发送到活动

如何使用警报管理器将数据从片段传递到广播接收器

用于更改日期的广播接收器

用于拔下耳机的广播接收器

广播接收器不适用于SMS

Android TV 中用于以太网 (RJ45) 和 USB 的广播接收器