服务绑定模板
服务端
- 定义Service,实现onBind方法,返回IBinder对象。返回的IBinder对象按客户端的需求,定义API给客户端调用
客户端
- 调用bindService,传入ServiceConnection(异步回调对象)
- 定义ServiceConnection,实现onServiceConnected方法,通过服务端返回的IBinder对象,将IBinder对象强制转换成与服务端约定的对象,调用其中的方法
public class Service {
public IBinder onBind(Intent intent);
}
public class ContextWrapper {
public boolean bindService(Intent service, ServiceConnection conn, int flag);
}
public interface ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) void
}
public interface IBinder {
}
服务绑定通信方式一:继承Binder
适用于客户端与服务端在相同的进程,不支持跨进程通信(IPC)
public class MyService extends Service {
private IBinder binder = new MyBinder();
public IBinder onBind(Intent intent) {
return binder;
}
public class MyBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
public Object doSomething() {
...
}
}
public class MyActivity extends Activity {
private MyServiceConnection myServiceConnection;
private MyService myService;
public void onCreate(Bundle savedInstanceState) {
button.setOnClickListener(this::onClick);
}
public void onStart() {
myServiceConnection = new MyServiceConnection();
bindService(intent, myServiceConnection , Context.BIND_AUTO_CREATE);
}
public void onStop() {
unBindService(myServiceConnection);
}
public void onClick(View v) {
Object result = myService.doSomething();
}
public class MyServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder binder) {
MyBinder myBinder = (MyBinder) binder;
myService = myBinder.getService();
}
}
}
服务绑定通信方式二:通过Messenger
解决继承Binder不能跨进程通信的问题,问题是Service只能串行处理客户端的消息,因此也不存在线程安全的问题,这里只描述单向消息传输(client -> Service)
public class MyService extends Service {
public IBinder onBind(Intent intent) {
HandlerThread thread = new HandlerThread(name, priority);
thread.start();
return new Messenger(new MyHandler(thread.getLooper())).getBinder();
}
}
public class MyHandler extends Handler {
public void handleMessage(Message msg) {
// do something based on the incoming message
}
}
public class MyActivity extends Activity {
private MyServiceConnection myServiceConnection;
private Messenger messenger;
public void onCreate(Bundle savedInstanceState) {
button.setOnClickListener(this::onClick);
}
public void onStart() {
myServiceConnection = new MyServiceConnection();
bindService(intent, myServiceConnection , Context.BIND_AUTO_CREATE);
}
public void onStop() {
unBindService(myServiceConnection);
}
public void onClick(View v) {
Message message = Message.obtain();
message.what = ..
messenger.send(message);
}
public class MyServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder binder) {
MyBinder myBinder = (MyBinder) binder;
messenger= new Messenger(binder);
}
}
}
服务绑定通信方式三:通过AIDL
服务端客户端公有
- 在src/main目录下新增aidl文件
app/src/main/aidl/com/company/IMyAidlInterface.aidl
- aidl文件格式
package com.company;
import com.company.MyPojo;
interface IMyAidlInterface {
int func(String str, in MyPojo myPojo, in Bundle bundle);
}
服务端
- 定义服务端的Service,onBind方法返回aidl定义的Stub实例
public class MyService extends Service {
public IBinder onBind(Intent intent) {
return binder;
}
private final IMyAidlInterface.Stub binder = new IMyAidlInterface.Stub() {
public int func(String str, MyPojo myPojo, Bundle bundle) {
....
}
}
}
- aidl支持并发处理,要考虑线程安全的问题;如果有耗时操作,要放到子线程
- 如果需要传递自定义对象,自定义对象必现实现Parcelable; 如果Bundle中有自定义对象(已实现Parcelable),读取Bundle中的数据之前,必须先调用setClassLoader
private final IMyAidlInterface.Stub binder = new IMyAidlInterface.Stub() {
public int func(String str, MyPojo myPojo, Bundle bundle) {
bundle.setClassLoader(getClass().getClassLoader());
MyObj myObj = bundle.getParcelable("obj");
}
}
客户端
- 调用bindService发起绑定,并定义ServiceConnection,在onServiceConnected方法获取binder实例
public MyActivity extends Activity {
IMyAidlInterface myAidlInterface;
private ServiceConnection connection = new ServiceConnection() {
public onServiceConnected(ComponentName name, IBinder service) {
myAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
}
private void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bind = findViewById(R.id.bind);
bind.setOnClickListener(this::callService);
}
public void onStart() {
Intent intent = new Intent();
intent.setComponent(new ComponentName(SERVER_PACKAGE_NAME, SERVER_SERVICE_NAME));
intent.setPackage(SERVER_PACKAGE_NAME);
bindService(intent, conection, BIND_AUTO_CREATE);
}
public void onStop() {
super.onStop();
unbindService(connection);
}
private void callService(View v) {
int result = myAidlInterface.func("hi", myPojo, bundler);
}
}
- 调用aidl方法时,必现捕获DeadObjectException(连接已断开)和SecurityException(客户端与服务地的aidl定义有冲突)