从已绑定的服务返回不同的绑定程序



我有一个服务,它已经通过AIDL被外部应用程序绑定。

但是,有一些服务请求需要启动Activity。 由于我无法从服务中调用startActivityForResult,因此我决定将本地活动也绑定到服务。

(伪代码)看起来像这样:

class MyService extends Service{
public IBinder onBind(Intent intent){
if (intent.hasExtra("LocalBindingRequest")){
return getLocalBinder();
else {
return getAidlBinder();
}
}
}
class ExternalApp extends Activity{
void someFunc(){
Intent i = new Intent(new ComponentName("com.my.pkg", "com.my.pkg.MyService");
bindService(i, myServiceConnection, Context.BIND_AUTO_CREATE);
}
}
class InternalApp extends Activity{
MyService mService;
void someFunc(){
Intent i = new Intent(new ComponentName("com.my.pkg", "com.my.pkg.MyService")
.putExtra("LocalBindingRequest", true);
bindService(i, myServiceConnection, Context.BIND_AUTO_CREATE);
}
public void onServiceConnected(ComponentName cn, IBinder service){
InternalBinder ib = (LocalBinder)service;
mService = ib.getService();
}
}

流程是这样的:

  • ExternalApp 绑定到 AidlBinder
  • 外部应用程序调用需要服务才能启动活动的函数
  • 服务启动活动
  • 内部活动尝试绑定
  • 我收到异常(似乎没有在onBindonServiceConnected中遇到断点)

java.lan.ClassCastException: AidlService 不能强制转换为 InternalBinder


服务是否可以返回不同的活页夹?

如果没有,我该怎么办,将结果传播回已绑定的 MyService?

好的,我应该阅读onBind(Intent)中的文档

意向:用于绑定到此服务的意向,如提供给 请注意,包含在 此时的意图不会在这里看到。

这就是为什么我得到了Aidl服务。修复将是:

class InternalApp extends Activity{
MyService mService;
void someFunc(){
Intent i = new Intent(new ComponentName("com.my.pkg", "com.my.pkg.MyService");
i.setAction("LocalBindingRequest");
bindService(i, myServiceConnection, Context.BIND_AUTO_CREATE);
}
public void onServiceConnected(ComponentName cn, IBinder service){
InternalBinder ib = (LocalBinder)service;
mService = ib.getService();
}
}

class MyService extends Service{
public IBinder onBind(Intent intent){
if ("LocalBindingRequest".equals(intent.getAction()){
return getLocalBinder();
else {
return getAidlBinder();
}
}
}

我们可以为每个绑定请求使用单独的活页夹

问题已经回答了,但我想提供一个示例,说明如何使用 Messenger 的活页夹而不是 AIDL 完成此操作。

可以使您在服务的onBind()中返回的Binder具有适应性和动态性,以适应连接到服务的客户端是否是来自另一个进程/应用程序的组件(在这种情况下,我们希望将Messenger的绑定器返回给他们以建立IPC),或者连接到服务的客户端是否是我们自己的进程/应用程序中的组件(在这种情况下,我们希望返回自定义Binder对象)具有对服务的引用)。

我们需要做的就是指定一个带有意图的操作,用于从任一客户端绑定服务,在服务中,我们过滤该操作,并根据意图的操作返回 Binder。

首先,我们使用以下意图筛选器在清单中声明 MyService:

<service
android:name=".MyService"
android:exported="true">
<intent-filter>
<action android:name="foreignProcess" />
<action android:name="localComponent" />
</intent-filter>
</service>

然后在 MyService 中,我们声明,我们确保根据意图的操作在 onBind() 中返回不同的 Binders:

class MyService: Service() {
private var clientMessenger: Messenger? = null
private val incomingHandler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msgFromClient: Message) {
super.handleMessage(msgFromClient)
clientMessenger = msgFromClient.replyTo
val receivedBundle = msgFromClient.data
}
}
// public method that we can call from Activities/Fragments, etc that bind to our service.
fun doStuff() {
}
// depending on the action of the intent that was used to bind to the service, we return the appropriate Binder.
override fun onBind(intent: Intent?): IBinder {
return when (intent?.action) {
"localComponent" -> MyBinder()
"foreignProcess" -> Messenger(incomingHandler).binder
else -> Messenger(incomingHandler).binder
}
}
inner class MyBinder : Binder() {
val service: MyService
get() = this@MyService
}
}

现在,在我们自己的应用程序中存在的组件(如活动或片段)(即与服务存在于同一进程中)中,我们使用操作"localComponent"创建一个意图,并使用它来绑定到服务:

fun bindToServiceThroughMyLocalComponent(context: Context) {
val conn = object: ServiceConnection {
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
val myService = (binder as MyService.MyBinder).service
myService.doStuff()
}
override fun onServiceDisconnected(name: ComponentName?) {}
}
val intent = Intent(context, MyService::class.java).apply {
setAction("localComponent")
}
context.bindService(intent, conn, Context.BIND_AUTO_CREATE)
}

在客户端应用程序(存在于不同的进程中)中,我们使用操作"foreignProcess"创建一个意图,并使用它来绑定到服务:

fun bindToServiceThroughForeignProcess(context: Context) {
val incomingHandler = object: Handler(Looper.getMainLooper()) {
override fun handleMessage(msgFromService: Message) {
super.handleMessage(msgFromService)
val receivedBundle = msgFromService.data
}
}
val conn = object: ServiceConnection {
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
val clientMessenger = Messenger(incomingHandler)
val clientMessage = Message.obtain(null, 0, clientMessenger)
val bundle = Bundle()
bundle.putString("message", "hello world")
clientMessage.data = bundle
clientMessage.replyTo = clientMessenger // pass our clientMessenger to the clientMessage to establish IPC
Messenger(binder).send(clientMessage)
}
override fun onServiceDisconnected(name: ComponentName?) {}
}
val intent = Intent("foreignProcess")
context.bindService(intent, conn, Context.BIND_AUTO_CREATE)
}

现在,我们服务的 onBind() 根据不同客户端在其意图操作中指定的内容返回不同的 Binders。

最新更新