我们知道Service开启的方式有俩种:
- startService
- bindService
使用startService开启服务, 一般都不和Service进行交互,
而使用bindService开启服务,一般都需要和Service进行交互,因此,如果想获取Service,并和它进行交互,请使用bindService
使用bindService有如下几种情况
-1,service和client都属于同一个process
-2, service和client属于不同的process, 给service发送消息
-3, service和client属于不同的process, 需要调用service(其实是onBind()方法返回的ibinder对象)的多个方法
第一种方式,很简单,直接创建一个内部类继承自Binder, 然后在service的onBind()方法中返回此内部类的对象
第二种方式,我们可以使用Messenger的getBinder()对象作为onBind的返回值。
第三种方式,是采取aidl方式进行通信。
今天,我们只说第二种,分析第二种的原理:
首先,创建一个service,并且在AndroidManifest.xml里面配置,并加上android:process属性
public class MessagerService extends Service {
public MessagerService() {
}
//创建一个handler
private Handler ipcHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("LF", "msg.what : " + msg.what + ", msg.arg1 : " + msg.arg1);
Log.e("LF", "handleMessage thread : " + Thread.currentThread() + ", process : " + Process.myPid());
}
};
//使用ipcHandler构建一个Messenger对象
private Messenger messenger = new Messenger(ipcHandler);
@Override
public IBinder onBind(Intent intent) {
Log.e("LF", "onBind pid : " + Process.myPid());
//将messenger中的binder返回。
return messenger.getBinder();
}
}
//在manifest中的配置, 加上process属性,就表示运行在不同的进程中
<service
android:name=".MessagerService"
android:process=".remoteMessenger"
android:enabled="true"
android:exported="true">
</service>
首先来看一下Messenger messenger = new Messenger(ipcHandler); 打开Messenger的源码,通过handler构造一个Messenger, 内部只是调用handler的getIMessenger()方法,将其返回值保存在mTarget成员变量。
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
在来看一下onBind()方法中返回的messenger.getBinder()方法在Messenger类中的定义
public IBinder getBinder() {
//它返回的是mTarget.asBinder对象
return mTarget.asBinder();
}
通过前面构造Messenger时,我们清楚mTarget是Handler中的getIMessenger()的返回值, 我们来看一下此方法
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
从方法的定义可以看到getIMessenger()方法返回的是MessengerImpl对象,
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
MessengerImpl类是Handler类的内部类,它继承自IMessenger.Stub类,看到Stub,我们是不是想到了AIDL文件自动生成的内部类呀,Stub类是继承自Binder的,所以MessengerImpl是一个Binder对象。
我们也来看一下此IMessenger.java类
public interface IMessenger extends android.os.IInterface
{
public static abstract class Stub extends android.os.Binder implements android.os.IMessenger {
......
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
public static android.os.IMessenger asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.os.IMessenger))) {
return ((android.os.IMessenger)iin);
}
return new android.os.IMessenger.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder() {
return this;
}
......
和我们自己创建的aidl文件之后,系统给我们自动生成的一模一样, 因此我们在onBind()方法中返回的mTarget.asBinder() ,就等于handler.getIMessenger().asBinder() ,最后其实就是MessengerImpl, 它是Stub的子类。和我们自己创建aidl一样, 至此,服务端的代码分析完了, 我们接下来看一下客户端。
客户端的调用, 和正常的bindService一样,采取显示intent的方式,(android 5.0以上必须采取显示intent的方式开启服务, 否则会抛异常)
private Messenger mMessenger;
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e("LF", " iBinder : " + iBinder);
//根据iBinder创建一个Messenger对象
mMessenger = new Messenger(iBinder);
isConnection = true;
try {
iBinder.linkToDeath(new MyDeathRecipient(), 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
//开启服务的代码
@Override
public void onClick(View view) {
switch (view.getId()) {
//开启服务端的代码
case R.id.bindMessager:
Intent messagerIntent = new Intent(this, MessagerService.class);
this.bindService(messagerIntent, conn, BIND_AUTO_CREATE);
break;
case R.id.unBindMessager:
//unbind service的代码
if (isConnection) {
this.unbindService(conn);
isConnection = false;
}
break;
case R.id.invokeIPC:
//调用服务端的代码
if (isConnection && mMessenger != null) {
Message message = Message.obtain();
message.what = 10;
message.arg1 = 21;
try {
mMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
default:
}
}
当服务开启之后,我们在onServiceConnected()方法中可以获取到service端返回的iBinder对象。此iBinder对象在非IPC中,它就是MessengerImpl对象,如果在IPC中,那么此iBinder是BinderProxy, 它是一个代理。
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e("LF", " iBinder : " + iBinder);
mMessenger = new Messenger(iBinder);
isConnection = true;
try {
iBinder.linkToDeath(new MyDeathRecipient(), 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
我们来看一下new Messenger(iBinder) 这句话,底层做了啥?
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
从上述代码里面可以很清楚的看到,其实它就是我们之前使用aidl的写法,将IMessenger.Stub.asInterface返回的对象,赋值给mTarget对象
来看一下IMessenger.Stub 中asInterface()方法的定义
public static android.os.IMessenger asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
//首先在本地找,如果找到,就直接返回
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.os.IMessenger))) {
return ((android.os.IMessenger)iin);
}
//本地没有,就返回Stub.Proxy内部类对象
return new android.os.IMessenger.Stub.Proxy(obj);
}
这里我们先不分析asInterface底层实现,只需要记住,如果是IPC,客户端获取到的是proxy.所以,这里mTarget是IMessenger.Stub的内部proxy
我们再来看一下mMessenger.send(message);这句底层实现
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
其实就是调用mTarget的send。也就是调用proxy的send
@Override public void send(android.os.Message msg) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((msg!=null)) {
_data.writeInt(1);
msg.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_send, _data, null, android.os.IBinder.FLAG_ONEWAY);
} finally {
_data.recycle();
}
}
static final int TRANSACTION_send = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
我们看到是调用mRemote的transact方法,mRemote对象是我们传入的iBinder对象,其实最终会调用Stub的onTransact方法, 然后在onTransact方法里面进行switch根据传入的TRANSACTION_send 判断,最后调用的是MessengerImpl的send方法
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
最终就会走正常的handler 的流程。
从以上的分析,可以看出,Messenger底层也是使用AIDL来实现的。在服务端通过Handler来构建一个MessengerImpl 的Bindler对象,将此Bindler对象通过onBind()方法返回, 在客户端,以bindService开启服务之后, 根据服务端传回来的iBinder对象创建一个Messenger对象, 这样客户端中的Messenger对象,就获取到了service端的IMessenger的代理(IPC, 非IPC是MessengerImpl对象)。这样,客户端和服务端,就可以通过Messenger的send方法进行通信了。
当然使用Messenger也可以从client端向service端的子线程发送handler消息, 只需要在service端构建Messenger的时候,传入一个带子线程Looper对象的Handler即可。
public class MessagerService extends Service {
public MessagerService() {
}
private Handler ipcHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("LF", "msg.what : " + msg.what + ", msg.arg1 : " + msg.arg1);
Log.e("LF", "handleMessage thread : " + Thread.currentThread() + ", process : " + Process.myPid());
}
};
private class MyAsyncHandler extends Handler {
MyAsyncHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("LF", "msg.what : " + msg.what + ", msg.arg1 : " + msg.arg1);
Log.e("LF", "handleMessage thread : " + Thread.currentThread() + ", process : " + Process.myPid());
}
}
private Looper mHandlerLooper;
private MyAsyncHandler myAsyncHandler;
private Messenger mAsyncMessenger;
@Override
public void onCreate() {
super.onCreate();
//构建一个HandlerThread ,HandlerThread内部开启一个子线程,并且创建一个Looper,并进行loop循环。
HandlerThread handlerThread = new HandlerThread("MessengerHandlerThread");
handlerThread.start();
this.mHandlerLooper = handlerThread.getLooper();
this.myAsyncHandler = new MyAsyncHandler(mHandlerLooper);
//根据此Handler去构建一个Messenger对象
mAsyncMessenger = new Messenger(myAsyncHandler);
}
private Messenger messenger = new Messenger(ipcHandler);
@Override
public IBinder onBind(Intent intent) {
return mAsyncMessenger.getBinder();
}
@Override
public void onDestroy() {
super.onDestroy();
this.mHandlerLooper.quit();//自己开启的loop一定要记得退出
}
}
唯一注意一点的是,自己创建的Looper一定要记得调用quit或者quitSafe退出,否则,线程会一直存在。
如果服务端需要给客户端回应,那么在client端也构建一个Messenger对象,将Messenger对象赋值给message的replyTo,发送给service端,
Messenger 的内部是使用handler来处理消息的,所以,它是一个串行的过程。如果要处理并发的请求,或者跨进程调用service端的方法,请使用AIDL