android进程间通信采用的是binder机制.
应用场景:1.ActivityManagerService(extends Binder)、WindowManagerService 在system_server进程
应用程序要跨进程方法它们的方法。
2.在应用程序之间要互相访问,比如音乐中的MediaPlaybackService(extends Service),锁屏apk
调用其MediaPlaybackService中的方法来播放music。
工具:AIDL可以把一个 定义了包含MediaPlaybackService所有方法的.aidl接口文件编译成一个进程间通讯的类,
IMediaPlaybackService.Stub(extends Binder),该类包含了
一个内部类Proxy,Proxy工作在客户端,把请求transact到服务器端Stub的onTransact方法进行处理。
是不是有点神奇,一个类的横跨两个进程,即客户端发送请求和服务器处理请求都在这个类里面处理了。
private android.os.IBinder mRemote; public void openFile(java.lang.String path) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(path); mRemote.transact(Stub.TRANSACTION_openFile, _data, _reply, 0); _reply.readException(); }
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { case TRANSACTION_openFile: { data.enforceInterface(DESCRIPTOR); java.lang.String _arg0; _arg0 = data.readString(); this.openFile(_arg0); reply.writeNoException(); return true; }
比如音乐应用中有一个MediaPlaybackService extends Service,如果锁屏要访问这service中的方法,需要如下方法。
1.androidManifest.xml中service添加export = true;
2.增加IMediaPlaybackService.aidl并且修改Android.mk 编译 生成IMediaPlaybackService.java
3.MediaPlaybackService增加mBinder 复写onBind方法
private final IBinder mBinder = new ServiceStub(this);
@Override
public IBinder onBind(Intent intent) {
mDelayedStopHandler.removeCallbacksAndMessages(null);
mServiceInUse = true;
return mBinder;
}
4.
static class ServiceStub extends IMediaPlaybackService.Stub { WeakReference<MediaPlaybackService> mService; ServiceStub(MediaPlaybackService service) { mService = new WeakReference<MediaPlaybackService>(service); } @Override public boolean open(long [] list, int position) { return mService.get().open(list, position); } @Override public boolean openList(long [] list, int position, boolean forceShuffle, String channelName) { return mService.get().openList(list, position, forceShuffle, channelName); }
调用进程也需要IMediaPlaybackService.aidl 。
myService = IMediaPlaybackService.Stub.asInterface(service); 获得IMediaPlaybackService.Stub.Proxy对象
之后就是IMediaPlaybackService.Stub.ProxyIMediaPlaybackService.Stub直接通过onTransact Transact 进行binder通信。
=============================================================================================
Activity与Service[四大组件之一]通信的方式有三种:
1. bindService + 继承Binder类 同一个进程
2. bindService+AIDL 可以在不同进程,方法类似App 调用 SystemServer进程的PowerManagerService中的方法
3.Messenger
方法一:
这个方式只有当你的Acitivity和Service处于同一个Application和进程时,才可以用,比如你后台有一个播放背景音乐的Service,这时就可以用这种方式来进行通信。
用例子来说明其使用方法:
1. 来看Service的写法:
在Service里定义一个内部类,Binder的子类,通过这个类,把Service的对象传给Activity,这样Activity就可以调用Service里的公用方法和公用属性了,但这种方式,一定要在同一个进程和同一个Application里。
2. 再看相应Activity的代码:
这里就是通过IBinder来得到LocalService对象,再去调用其Public方法。
方法三:使用Messenger
上面的方法只能在同一个进程里才能用,如果要与另外一个进程的Service进行通信,则可以用Messenger。
其实实现IPC的方式,还有AIDL,但推荐使用Messenger,有两点好处:
1. 使用Messenger方式比使用AIDL的方式,实现起来要简单很多
2. 使用Messenger时,所有从Activity传过来的消息都会排在一个队列里,不会同时请求Service,所以是线程安全的。如果你的程序就是要多线程去访问Service,就可以用AIDL,不然最好使用Messenger的方式。
不过,其实Messenger底层用的就是AIDL实现的,看一下实现方式,先看Service的代码:
再看一下Activity的代码:
注意:以上写的代码只能实现从Activity向Service发送消息,如果想从Service向Activity发送消息,只要把代码反过来写就可以了。