如何在服务和活动之间进行最佳通信?

7
现在,Activity可以使用以下三种方式之一连接到服务: 我认为BroadcastReceivers是最简单的通信方式,但我在想为什么要使用其他方式?换句话说,何时使用messengers或AIDL将比broadcastreceivers更好?

1
你应该首先考虑你的服务是否在与你的活动相同的进程中运行,或者它是在不同的进程中运行,然后再进行处理。 - Eido95
是的,我以前使用过绑定,在我的最新项目中,我使用了广播,而且广播更容易使用。 - yeahman
4个回答

13

我通常倾向于使用LocalBroadcasts。它们就像真正的广播一样,但仅对您的应用程序可见。首先,您必须像处理正常广播一样创建一个BroadcastReceiver

private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if(Intent.SOME_ACTION.equals(action)) {
            // Do your work
        }
    }
};

您可以使用以下方式注册和注销 Broadcast Receiver :
@Override
public void onResume() {
    super.onResume();

    IntentFilter intentFilter = new IntentFilter(Intent.SOME_ACTION);

    LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getActivity());
    manager.registerReceiver(broadcastReceiver, intentFilter);
}

@Override
public void onPause() {
    super.onPause();

    LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getActivity());
    manager.unregisterReceiver(broadcastReceiver);
}

最后,您可以从Service或应用程序中的任何其他位置发送广播,如下所示:

Intent intent = new Intent(Intent.SOME_ACTION);

LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getActivity());
manager.sendBroadcast(intent);

2
同意。这个或第三方消息总线(Square的Otto,greenrobot的EventBus)是当前最佳实践。 - CommonsWare
“Messengers”并不常用,这也是为什么关于此主题的文档如此少的原因。它们主要用于在不同进程之间进行通信。 - Xaver Kapeller
你不能在不同的进程之间使用LocalBroadcastManager(例如,在活动和运行在不同进程上的服务之间进行通信时)。 - Manuela

12
您可以在应用程序中使用BroadcastReceiver来实现ServiceActivity之间的通信。 MessengerAIDL主要用于应用程序需要与其他进程(IPC)进行通信的情况。在这种情况下,您的接口应该具有一个定义了响应不同类型的Message对象的HandlerService
现在,MessengerAIDL之间的区别非常简单。当您使用Messenger时,它会将所有请求排队到一个单独的线程中。因此,您的Service不必是线程安全的。如果您希望Service同时处理多个请求,则可以直接使用AIDL。在这种情况下,您的Service必须具备多线程能力并构建为线程安全。实际上,Messenger是在AIDL之上实现的。
为了更好地理解,请查看绑定服务
您还应该查看来自BroadcastReceiver或通过Handler的Messenger的答案。

3

Xaver Kapeller的答案确实很好。然而,它有一个(主要)缺点:广播可能会被错过。

当用户离开Activity(例如显示最近的应用程序)时,您需要注销您的BroadcastReceiver。如果在那个时候发送广播,则您的Activity将无法接收到它。当返回到Activity时,它可能处于无效状态。


使用ResultReceiver,您仍然可以在这种情况下接收结果。此外,ResultReceiver是可parcelable的,因此您可以在生命周期事件中保存和恢复它。
但是,这会导致一些额外的开销,这就是为什么我创建了这个实验性库来简化它。目前它只使用IntentService,但应该很容易扩展。


是的,广播可能会被错过,但通常如果您的应用程序绝对依赖于接收广播,那么您正在做一些错误的事情。本地广播永远不应该用于实际传输数据或类似的内容。本地广播的一个用例是,您通知一个“Fragment”任务已完成或数据已更改并需要重新加载,换句话说,这些与应用程序本身的状态无关,它们只提供额外的 - 但基本上是不必要的 - 信息。 - Xaver Kapeller

2
如果您的服务仅被本地应用程序使用,并且不需要在进程之间工作,则可以实现自己的Binder类,为客户端提供对服务中公共方法的直接访问。
注意:这仅适用于客户端和服务在同一应用程序和进程中的情况,这是最常见的情况。
扩展Binder类:http://developer.android.com/guide/components/bound-services.html#Binder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接