Binder机制分析【二】-Binder服务/客户端实现举例

本文深入探讨了Android系统中Binder机制的实现原理及其在跨进程通信中的应用,通过实例详细展示了如何利用Binder机制实现Activity与Service之间的高效沟通。文中不仅对比了直接继承Binder与使用AIDL两种实现方式的区别,还提供了处理服务通信生命周期的方法,包括如何避免Service随Activity退出而销毁。此外,文章还解释了如何通过简单的步骤完成服务的绑定与解绑,以及在多媒体播放场景中如何确保服务的生命周期不受Activity状态的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前一章说了下Binder机制的实现分析,这章就主要通过实际的例子来看看,具体的服务端创建。一般而言,同一个进程里的沟通称之为短程沟通,进程间的沟通称之为远程沟通,短程沟通的效率远高于远程沟通,但是Android提供的Binder机制就提供了高效率的远程沟通。
下面通过Activity与Service之间的沟通为例,列举出2种实现方式。
例子一:通过直接继承Binder实现
1. 实现Binder类
public class MyBinder extends Binder {
private Context mContext;
public MyBinder(Context context){
mContext = context;
}
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
reply.writeString(data.readString()+" mp3");
switch(code){
case 1:
MyMediaPlayer.getIntance(mContext).play();
break;
case 2:
MyMediaPlayer.getIntance(mContext).stop();
break;
default:
break;
}
return true;
}
}

该类继承了Binder类,就必须实现onTransact方法,与客户端的transact方法相对应。其中参数code代表客户端调用码,决定在服务器端调用哪个方法,和transact端的保持一致,data是请求参数,由客户端设置,reply为返回参数,服务器端设置。Flags表示ipc通信方式。0表示双向,1表示单向。
2. 实现service类
public class MyService extends Service {
private Binder mBinder = null;
@Override
public IBinder onBind(Intent arg0) {
Log.e("XXX", "onBind");
return mBinder;
}

@Override
public void onCreate() {
super.onCreate();
mBinder = new MyBinder(this);
Log.e("XXX", "onCreate");
}
}

Service相对简单,主要是初始化Binder对象,并且在onBind中返回。
3. Activity与service之间的沟通
首先需要创建ServiceConnection对象,并且在bind时返回Binder对象
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("XXX", "onServiceDisconnected");
}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIBinder = service;
Log.e("XXX", "onServiceConnected");
}
};

其次,调用bindService绑定服务。
Intent intent = new Intent("com.eric.ipc.binder");
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);

最后,在需要调用服务器端方法的地方,通过transact进行沟通,这里传递的参数必须是Parcel的。
Parcel send_data = Parcel.obtain();
send_data.writeString("play");
Parcel reply_data = Parcel.obtain();
mIBinder.transact(1, send_data, reply_data, 0);

由此可见,这种方法提供的沟通手段比较单一,只能通过transact进行沟通,如果服务器端的接口很多,这样调用起来不太方便,所以Android提供了一种更为简单的方式来实现-AIDL。
AIDL定义了Proxy/Stub封装了IBinder接口,提供了更加方便的新接口。
例子二:通过AIDL实现
1. 单一aidl文件接口
package com.eric.ipc.aidl;
interface IMediaPlayer {
void play();
void stop();
}

该接口文件以aidl结尾,中间封装了2个方法,该文件生成后,会在gen目录下自动生成对应的java文件,里面包含了具体的类别继承,反向呼叫等实现。
2. 实现Binder类
public class MyBinder extends IMediaPlayer.Stub {
private Context mContext;
public MyBinder(Context context){
mContext = context;
}
@Override
public void play() throws RemoteException {
MyMediaPlayer.getIntance(mContext).play();
}
@Override
public void stop() throws RemoteException {
MyMediaPlayer.getIntance(mContext).stop();
}
}

现在的实现继承接口改为了aidl类文件的Stub,此处需要实现接口中的2个接口方法
3. 实现service类
此处同例一保持一致
4. activity与service之间的沟通
首先,需要实现ServiceConnection对象,注意返回binder对象时与例一之间的差别。
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("XXX", "onServiceDisconnected");
}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIBinder = IMediaPlayer.Stub.asInterface(service);
Log.e("XXX", "onServiceConnected");
}
};

其次,需要绑定服务,方法同例一
最后,具体调用服务器端接口
mIBinder.play();

总结:
2种方法都可以实现跨进程通信,但是aidl实现相对简单,接口直接调用。
问题:
1.如果我们想保持和 Service 的通信,又不想让 Service 随着 Activity 退出而退出呢?你可以先 startService() 然后再 bindService() 。当你不需要绑定的时候就执行 unbindService() 方法,执行这个方法只会触发 Service 的 onUnbind() 而不会把这个 Service 销毁。这样就可以既保持和 Service 的通信,也不会随着 Activity 销毁而销毁了。
2.Activity has leaked ServiceConnection异常
这个异常是由于在启动应用时绑定了service,退出时没有接触绑定导致,可以在退出时调用unbindService()方法解决。
3.在先startService(),然后bindService()的情况下,在退出时
1).如果只调用unbindService(),在第一次会调用onUnbind,然后再次绑定时,通过start启动,再退出是不会调用onUnbind。
2).如果调用unbindService()和stopService,整个service会调用ondestory进行销毁。
3.在通过MediaPlayer播放音乐时,网上都说如果在activity中播放,在activity退出时,音乐播放会停止,这个纯粹是他妈的扯淡,我以前还对此坚信不疑。MediaPlayer播放音乐,会重新启动一个service进行播放,如果你的activity或service已经destory了,是不影响播放service的生命周期的。


例子源码见附件

本章介绍了Binder服务器的实现及举例说明了binder客户端与服务端的交互,下一章介绍下Service是如何绑定Binder的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值