57

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

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

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

现在的问题是,您认为回调方法是否比BroadcastReceiver仅在单个应用程序内部使用的方法更好(更轻、更干净、更快..)?(请注意,我没有将 AndroidService用于后台工作.. 只是AsyncTaskThreads)

谢谢!

4

5 回答 5

86

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

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

专业版

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

反对

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

关于 - 方法的一些要点BroadcastReceiver

专业版

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

反对

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

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

于 2012-05-20T10:31:13.623 回答
6

我看不出你BroadcastReceiver在你的情况下使用会得到什么。回调,或者更好的可能Handlers是这样做的方式。BroadcastReceiver当您不知道订阅者是谁时,这很好。

于 2012-05-13T21:27:19.863 回答
3

我将在您已经收到的其他出色答案中添加另一个选项...

您不必创建广播接收器来接收 Intent。在您的 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 中,这样它就不会创建您的活动的新实例(如果一个已经在运行)。

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

于 2012-05-16T16:15:46.397 回答
2

如果您需要跨应用程序发送广播,则应该使用广播接收器,而回调(或 Alex 建议的处理程序)更适合您的情况。

如果您想使用这两个以外的,请考虑使用Observer(android 中包含的接口)和委托。

对于代表,请考虑这个 SO 帖子

于 2012-05-16T12:55:15.423 回答
1

不确定目标是什么,但如果您希望保持使用意图和广播接收器的相同想法,并且想要比普通广播接收器更好的性能和安全性,您可以试试这个演示,在 android 支持库中可用:

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

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

于 2012-05-16T20:30:11.167 回答