为啥 AIDL/Messenger 绑定到服务?

Posted

技术标签:

【中文标题】为啥 AIDL/Messenger 绑定到服务?【英文标题】:Why is AIDL/Messenger bound to a Service?为什么 AIDL/Messenger 绑定到服务? 【发布时间】:2015-01-09 16:15:27 【问题描述】:

场景:我有一个 Controller(普通 Java 类),它必须能够引导多个 Slaves。

Slave 的性质可能不同,因此它可以是:

    Service,我们称之为ServiceSlave:这个对象的生命周期通常与应用程序的组件不同(也就是说,它不依赖于当前的活动) 一个简单的 Java 类,比如 ObjectSlave:这个对象的生命周期在某种程度上受限于它的创建范围(比如当前活动)

这两种Slaves 的共同点是它们可以驻留在不同的进程中


因为这最后一个“要求”,我立即将注意力转向AIDL/Messenger,作为ControllerSlave之间的通信形式,因为它提供了IPC。

但是,似乎AIDL(以及Messenger,因为它也应该基于AIDL)只有在您使用Service时才被定义 .也就是说,如果没有IBinder 对象,我无法实现基于AIDL 的接口,而onServiceConnected 方法中通常会提供该对象。

第一个问题AIDL 真的只能在处理Service 时使用吗?如果是,为什么会这样?

现在,考虑一下我的情况。就像任何其他优秀的开发人员一样,我想编写一个单一的、优雅的界面,允许Controller 引导每个Slave,不管它们的性质如何。到目前为止,我想到的唯一解决方案是使用 Intents 和 BroadcastReceivers,所有这些都方便地包装在专用的 Java 类中。

第二个问题:这是唯一可行的方法吗?我在监督什么吗?


编辑

我想我应该详细说明Controller 元素的实际作用。它是一个与订阅它的几个 UI 小部件松散耦合的组件。它的设计(自愿)使其不需要引用Context。因此它不需要直接使用 UI 小部件,但这些小部件又依赖于Controller

【问题讨论】:

好的,根据您编辑的信息,我对 Controller/Slave 范式的真正目标感到困惑。如果它完全在您的应用程序中的Activity 内部(不需要Context),那么您根本不需要Service、AIDL 或Messenger。当您跨越进程边界或 (Service) 正在运行的不是以 UI 为中心的东西时,这些都将被使用。如果您只是将其用作内部发布-订阅类型系统,那么您必须定义类和接口。话虽如此,您可能希望将 EventBus 或 Otto 视为可能的 3rd 方助手。 好的,所以我在解释这一点时显然有问题:) 我的主要问题是关于如何在 ControllerSlave 之间进行通信,后者可能是也可能不是 @987654354 @。通信必须是进程间的(因为ControllerSlave可能运行在不同的进程上),但也可能在同一个进程内。 但是,Controller 是否仅在拥有的 Activity 运行时出现? 不,在某些情况下Controller 不绑定到Activity,而是存在于Service 中。 【参考方案1】:

这是一个很好的问题,但不是一个简单的问题。像大多数事情一样,有多种方法可以解决这类问题。首先要检查的是您的Controller 是否需要或使用 UI 组件。如果没有,那么您需要将其封装在Service 中。 Activity 生命周期只有当它是屏幕上的当前事物时才会运行。一旦用户按下 HOME 或 BACK,它就会分别停止或销毁。通过通知或从您的应用程序中启动另一个应用程序将产生类似于按 HOME 的效果:您的 Activity 将被暂停。

因此,假设您不需要/想要您的 Controller 的 UI,您可以使用很多东西:

    通过公开自定义 AIDL 接口使您的服务成为“绑定”服务。不难,但也不是为了装腔作势。 让您的服务响应自定义Intents 以采取一些行动。然后Service 可以回火广播或启动特定的“从属”Activity。如果对此感兴趣,请探索使用 IntentService 来更好地管理线程并防止您的应用出现 ANR。 与上一个类似,使用自定义Intent 并让您的从属发送一个Messenger 对象,它在Intent 中作为额外对象创建。此时Service 可以向Messenger 发送消息,该消息由从属Activity 拥有,并将被传递到特定的Handler

对于选项 2 和 3,您不需要自定义 AIDL 公开接口。正确的是,如果要使用绑定服务,则必须定义 AIDL 接口,并且您的 Service.onBind() 方法必须返回您的实例binder 接口存根实现。

综上所述,您可以使用 3 种方法中的任何一种来实现使用位于 ActivityService 实例中的从属类的目标。使用 AIDL 或 Messenger 方法的优点是减少了上下文切换(更有效),因为您不发送 Intent 对象。每次发送Intent 时,发件人都会联系在系统进程中运行的ActivityManagerService,以解析Intent 的发送位置。使用 AIDL 和 Messenger,只有最初的 bindService()startService() 呼叫会到达 ActivityManagerService。之后,使用两个进程之间的直接绑定器执行通信。

【讨论】:

不错的聚合!您能指出使用这些概念的开源原生应用程序吗?【参考方案2】:

原来AIDLBinder 没有绑定到Services。

虽然IBinder 引用确实仅在绑定到Service 时提供,但框架提供了Binder 类,该类已经实现了IBinder 接口。

此外,Binder 实例跨进程透明地工作,它不需要存在于Service 上下文中。


[还在阐述中,会提供一个如何直接使用Binder实例来实现结构的方案]

【讨论】:

以上是关于为啥 AIDL/Messenger 绑定到服务?的主要内容,如果未能解决你的问题,请参考以下文章

跨进程通信之Messenger

为啥 WPF 支持绑定到对象的属性,但不支持绑定字段?

为啥 socket.gethostbyname(socket.gethostname) 只绑定到本地 IP 地址?

为啥事件处理程序只能在 IHttpModule 初始化期间绑定到 HttpApplication 事件?

为啥我收到“地址已在使用(绑定失败)”? [复制]

Android开发艺术探索——第二章:IPC机制(上)