为啥 AIDL/Messenger 绑定到服务?
Posted
技术标签:
【中文标题】为啥 AIDL/Messenger 绑定到服务?【英文标题】:Why is AIDL/Messenger bound to a Service?为什么 AIDL/Messenger 绑定到服务? 【发布时间】:2015-01-09 16:15:27 【问题描述】:场景:我有一个 Controller
(普通 Java 类),它必须能够引导多个 Slave
s。
Slave
的性质可能不同,因此它可以是:
Service
,我们称之为ServiceSlave
:这个对象的生命周期通常与应用程序的组件不同(也就是说,它不依赖于当前的活动)
一个简单的 Java 类,比如 ObjectSlave
:这个对象的生命周期在某种程度上受限于它的创建范围(比如当前活动)
这两种Slave
s 的共同点是它们可以驻留在不同的进程中。
因为这最后一个“要求”,我立即将注意力转向AIDL
/Messenger
,作为Controller
和Slave
之间的通信形式,因为它提供了IPC。
但是,似乎AIDL
(以及Messenger
,因为它也应该基于AIDL)只有在您使用Service
时才被定义 .也就是说,如果没有IBinder
对象,我无法实现基于AIDL
的接口,而onServiceConnected
方法中通常会提供该对象。
第一个问题:AIDL
真的只能在处理Service
时使用吗?如果是,为什么会这样?
现在,考虑一下我的情况。就像任何其他优秀的开发人员一样,我想编写一个单一的、优雅的界面,允许Controller
引导每个Slave
,不管它们的性质如何。到目前为止,我想到的唯一解决方案是使用 Intent
s 和 BroadcastReceiver
s,所有这些都方便地包装在专用的 Java 类中。
第二个问题:这是唯一可行的方法吗?我在监督什么吗?
编辑
我想我应该详细说明Controller
元素的实际作用。它是一个与订阅它的几个 UI 小部件松散耦合的组件。它的设计(自愿)使其不需要引用Context
。因此它不需要 或直接使用 UI 小部件,但这些小部件又依赖于Controller
。
【问题讨论】:
好的,根据您编辑的信息,我对 Controller/Slave 范式的真正目标感到困惑。如果它完全在您的应用程序中的Activity
内部(不需要Context
),那么您根本不需要Service
、AIDL 或Messenger
。当您跨越进程边界或 (Service
) 正在运行的不是以 UI 为中心的东西时,这些都将被使用。如果您只是将其用作内部发布-订阅类型系统,那么您必须定义类和接口。话虽如此,您可能希望将 EventBus 或 Otto 视为可能的 3rd 方助手。
好的,所以我在解释这一点时显然有问题:) 我的主要问题是关于如何在 Controller
和 Slave
之间进行通信,后者可能是也可能不是 @987654354 @。通信必须是进程间的(因为Controller
和Slave
可能运行在不同的进程上),但也可能在同一个进程内。
但是,Controller
是否仅在拥有的 Activity
运行时出现?
不,在某些情况下Controller
不绑定到Activity
,而是存在于Service
中。
【参考方案1】:
这是一个很好的问题,但不是一个简单的问题。像大多数事情一样,有多种方法可以解决这类问题。首先要检查的是您的Controller
是否需要或使用 UI 组件。如果没有,那么您需要将其封装在Service
中。 Activity
生命周期只有当它是屏幕上的当前事物时才会运行。一旦用户按下 HOME 或 BACK,它就会分别停止或销毁。通过通知或从您的应用程序中启动另一个应用程序将产生类似于按 HOME 的效果:您的 Activity
将被暂停。
因此,假设您不需要/想要您的 Controller
的 UI,您可以使用很多东西:
-
通过公开自定义 AIDL 接口使您的服务成为“绑定”服务。不难,但也不是为了装腔作势。
让您的服务响应自定义
Intent
s 以采取一些行动。然后Service
可以回火广播或启动特定的“从属”Activity
。如果对此感兴趣,请探索使用 IntentService
来更好地管理线程并防止您的应用出现 ANR。
与上一个类似,使用自定义Intent
并让您的从属发送一个Messenger
对象,它在Intent
中作为额外对象创建。此时Service
可以向Messenger
发送消息,该消息由从属Activity
拥有,并将被传递到特定的Handler
。
对于选项 2 和 3,您不需要自定义 AIDL 公开接口。正确的是,如果要使用绑定服务,则必须定义 AIDL 接口,并且您的 Service.onBind()
方法必须返回您的实例binder 接口存根实现。
综上所述,您可以使用 3 种方法中的任何一种来实现使用位于 Activity
或 Service
实例中的从属类的目标。使用 AIDL 或 Messenger
方法的优点是减少了上下文切换(更有效),因为您不发送 Intent
对象。每次发送Intent
时,发件人都会联系在系统进程中运行的ActivityManagerService
,以解析Intent
的发送位置。使用 AIDL 和 Messenger
,只有最初的 bindService()
或 startService()
呼叫会到达 ActivityManagerService
。之后,使用两个进程之间的直接绑定器执行通信。
【讨论】:
不错的聚合!您能指出使用这些概念的开源原生应用程序吗?【参考方案2】:原来AIDL
和Binder
没有绑定到Service
s。
虽然IBinder
引用确实仅在绑定到Service
时提供,但框架提供了Binder
类,该类已经实现了IBinder
接口。
此外,Binder
实例跨进程透明地工作,它不需要存在于Service
上下文中。
[还在阐述中,会提供一个如何直接使用Binder实例来实现结构的方案]
【讨论】:
以上是关于为啥 AIDL/Messenger 绑定到服务?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 socket.gethostbyname(socket.gethostname) 只绑定到本地 IP 地址?