Android BroadcastReceiver还是简单的回调方法?

时间:2012-05-13 21:03:31

标签: android multithreading callback broadcastreceiver

在我的项目中,我使用BroadcastReceiver作为来自长时间运行线程的回调(例如,通知活动下载已完成并从Worker Thread发送一些响应数据,以便活动可以向用户显示相应的消息..)。 要使用BroadcastReceiver,我每次使用时都必须小心注册和取消注册广播接收器,并且当我使用此方法进行更多不同的操作(例如下载)时,还要特别注意要发送的消息。 ,进行WebService调用等。)。而且,为了通过广播的意图发送自定义对象,我还需要制作对象Parcelable

与这种方法不同,我也看到了回调方法方法,它似乎比我使用的方法更简单。回调方法是简单的接口方法实现,可用于实现与应用程序消息传递中的BroadcastRecaiver相同的效果。 这种方法不需要Parcelable实现来返回复杂的对象而且它不使用像BroadcastReceiver这样的键。我认为不好的部分是我需要在我想调用a之前检查回调对象的null值回调方法..还要确保我从UI线程上的实现运行代码,这样我就可以更新UI而不会出错。

好的,我希望你明白我的意思:)。

现在的问题是,您认为回调方法比单个应用程序内部使用的BroadcastReceiver方法更好(更轻,更干净,更快......)? (请注意,我没有使用Android Service进行后台工作..仅AsyncTaskThread s)

谢谢!

5 个答案:

答案 0 :(得分:80)

这是一个非常有趣的问题,我遇到了同样的问题。在我看来,这两种机制都可以完全使用,正确的使用方法取决于您的使用案例。在决定之前,请考虑以下几点。

使用回调机制有一些好处,但也有局限性:

PRO

  • 实施简单明了。
  • 您可以在彼此交互的组件之间获得类型安全性。
  • 您可以返回任意对象。
  • 它简化了测试,因为你只需要在单元测试中注入模拟回调(例如通过mockito或类似的东西生成)。

CONTRA

  • 您必须切换到主线程才能进行UI操作。
  • 您只能拥有一对一的关系。没有进一步的工作,1到n的关系(观察者模式)是不可实现的。在这种情况下,我更喜欢Android的Observer / Observable机制。
  • 正如您已经说过的,如果回调可能是可选的,那么在调用回调函数之前,您总是必须检查null
  • 如果您的组件应该提供一种具有不同服务功能的服务API,并且您不希望只有几个通用回调函数的回调接口,则必须决定是否为每个服务函数提供特殊的回调接口或者您是否提供具有大量回调函数的单个回调接口。在后一种情况下,用于对API的服务调用的所有回调客户端都必须实现完整的回调接口,尽管大多数方法体都是空的。您可以通过实现具有空主体的存根并使您的回调客户端从该存根继承来解决此问题,但如果已经从其他基类继承,则这是不可能的。也许你可以使用某种动态代理回调(参见http://developer.android.com/reference/java/lang/reflect/Proxy.html),但它变得非常复杂,我会想到使用另一种机制。
  • 如果服务的调用者无法直接访问回调调用的客户端,则必须通过各种方法/组件进行传播。

关于BroadcastReceiver - 方法的一些观点:

PRO

  • 您在组件之间实现松耦合。
  • 您可以拥有1对n的关系(包括1对0)。
  • onReceive()方法始终在主线程上执行。
  • 您可以通知整个应用程序中的组件,因此通信组件不必相互“看到”。

CONTRA

  • 这是一种非常通用的方法,因此Intent传输的数据的编组和解组是一个额外的错误来源。
  • 如果您想要消除与其他应用的相关性,您必须使Intent的操作与众不同(例如,通过预先添加包名称),因为它们最初的目的是在应用程序之间进行广播。
  • 您必须管理BroadcastReceiver - 注册和取消注册。如果您想以更舒适的方式执行此操作,则可以实现自定义注释,以使用应注册的操作注释您的Activity,并实现一个基本Activity类,该类可以使用IntentFilter进行注册和取消注册s onResume() res。 onPause()的方法。
  • 正如您已经说过的,使用Intent发送的数据必须实现Parcelable接口,但此外还有严格的大小限制,如果您运输大量的话会导致性能问题您Intent的数据量。有关此问题的讨论,请参阅http://code.google.com/p/android/issues/detail?id=5878。因此,如果您要发送图像,例如,您必须将它们临时存储在存储库中,并发送相应的ID或URL以从Intent的接收方访问该图像,该接收方在使用后将其从存储库中删除。如果有多个接收器,这会导致进一步的问题(什么时候应该从存储库中删除图像,谁应该这样做?)。
  • 如果过度使用这种通知机制,应用程序的控制流可能会被隐藏,在调试时最终会绘制序列为Intent的图形,以了解触​​发了特定错误的内容或为什么会出现此通知链在某些时候被打破了。

在我看来,即使是移动应用也应该拥有至少2层的架构:UI层和核心层(带有业务逻辑等)。通常,长时间运行的任务在自己的线程中执行(可能通过AsyncTaskHandlerThread,如果在核心层内使用MessageQueue s),则应在此任务完成后更新UI完了。通常使用回调可以实现组件之间的紧密耦合,因此我更倾向于仅在一个层中使用此方法,而不是跨层边界进行通信。对于UI层和核心层之间的消息广播,我将使用BroadcastReceiver - 方法,使您可以将UI层与逻辑层分离。

答案 1 :(得分:6)

在您的案例中,我没有看到您使用BroadcastReceiver获得的收益。回调或更好的Handlers可能是这样做的。当你不知道订阅者是谁时,BroadcastReceiver会很好。

答案 2 :(得分:3)

我只会为你已经收到的其他好答案添加另一个选项......

您不必创建广播接收器来接收Intents。在您的Android清单文件中,您可以注册任何活动以接收意图:

<activity android:name=".MyActivity">
        <intent-filter >
              <action android:name="intent.you.want.to.receive" /> 
              <category android:name="android.intent.category.DEFAULT" /> 
        </intent-filter>     
....
</activity>

然后覆盖活动中的onNewIntent(Intent)方法以接收它。

要发送Intent,请使用Context.startActivity(Intent)方法。很可能你会想要将FLAG_ACTIVITY_SINGLE_TOP标志添加到你的Intent中,这样如果你的活动已经在运行,它就不会创建你的活动的新实例。

编辑:我刚注意到你在一个应用程序中运行。因此,简单的回调可能是最好的。上述解决方案适用于单个应用程序,但更适合不同的应用程序。我会留在这里,以防它帮助某人。祝你好运!

答案 3 :(得分:2)

应该使用Broadcastreceivers如果您需要跨应用程序发送广播,而回调(或Alex建议的处理程序)最适合在您的情况下使用。

如果您想使用除这两者之外的其他内容,请考虑使用Observer(Android中包含的界面)和委托。

对于代表,请考虑this SO post

答案 4 :(得分:1)

不确定目标是什么,但是如果你想保持使用intent和broadcastReceiver的相同想法,并希望比普通的broadcastReceivers更好的性能和安全性,你可以尝试这个演示,可以在android支持库中找到:< / p>

http://developer.android.com/resources/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.html

如果没有,您可以随时使用asyncTask,service,handlers等...