Binder又是什么?在这里我并不准备给出一个详尽、确切的答案——因为他太复杂了,深入的讲下去的话必将导致这篇博文失去重心。在这里我们只需要知道,它实现了IBinder接口,通过实现Binder类,我们的客户端可以直接通过这个类调用服务端的公有方法。另外,虽然从IPC的角度来讲,Binder是Android中的一种跨进程通信方式,但是其实一般service里面的Binder是不会涉及进程间通信的,所以其在这种情况下显得较为简单。
下面我们来看下通过继承Binder类实现客户端与服务端通信应该怎样做:
在service类中,创建一个满足以下任一要求的Binder实例:
包含客户端可调用的公共方法
返回当前Service实例,其中包含客户端可调用的公共方法
返回由当前service承载的其他类的实例,其中包含客户端可调用的公共方法
在onBind()方法中返回这个Binder实例
在客户端中通过onServiceDisconnected()方法接收传过去的Binder实例,并通过它提供的方法进行后续操作
可以看到,在使用这种方法进行客户端与服务端之间的交互是需要有一个强制类型转换的——在onServiceDisconnected()中获得一个经过转换的IBinder对象,我们必须将其转换为service类中的Binder实例的类型才能正确的调用其方法。而这强制类型转换其实就隐含了一个使用这种方法的条件:客户端和服务端应当在同一个进程中!不然在类型转换的时候也许会出现问题——在另一个进程中一定有这个Binder实例么?没有的话就不能完成强制类型转换。
下面是一个Google官方的例子:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
LocalBinder 为客户端提供 getService() 方法,以检索 LocalService 的当前实例。这样,客户端便可调用服务中的公共方法。 例如,客户端可调用服务中的 getRandomNumber():
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
当Activity进入onStart()状态时,就会尝试与目标service绑定,而当点击按钮时,如果绑定已经完成,就会调用service中的方法getRandomNumber(),并将其输出。
线程内通信基本上就是这样了,没什么复杂的地方。