很久没用跨进程通信了,然后等自己又要用的时候,网上一搜,千遍一律,还很渣,吐血~
工程有两份`MessengerService`&`MessengerActivity`,前个提供服务,后个访问服务。
跨进程通信
就多个apk互相通信,当然广播也是不错的。不过这里用的是Messenger和AIDL,并且都弄成双向的了。
Messenger
信使,底层说是也用的AIDL。用起来挺方便的。
MessengerService
1)AndroidManifest.xml声明权限
- <permission
- android:name="org.join.permission.SERVICE"
- android:protectionLevel="normal" >
- </permission>
- <uses-permission android:name="org.join.permission.SERVICE" />
为什么弄个带权限的呢?因为讨厌任何警告==。
2)注册MessengerService
- <service
- android:name="org.join.messenger.MessengerService"
- android:exported="true"
- android:permission="org.join.permission.SERVICE"
- android:process=":remote" >
- <intent-filter>
- <action android:name="org.join.service.MESSENGER" />
- </intent-filter>
- </service>
这里把权限加上了,不然最新ADT是会有个警告的。就一嘀咕的老头,讨人厌。
3)MessengerService核心代码
- public class MessengerService extends Service implements MessageCode {
- static final String TAG = "MessengerService";
- public static final String ACTION = "org.join.service.MESSENGER";
- // 第一步:新建
- final Messenger mMessenger = new Messenger(new Handler() {
- // 第二步:处理Message
- @Override
- public void dispatchMessage(Message msg) {
- switch (msg.what) {
- case CLNT_REQ_HELLO:
- toast("Hello!");
- Bundle data = new Bundle();
- data.putString("msg", "Who am I?");
- // 这个`msg.replyTo`是客户端的信使
- respClnt(msg.replyTo, SERV_RES_HAHA, data);
- break;
- case CLNT_REQ_SURPRISE:
- String s = msg.getData().getString("msg");
- toast("Surprise! " + s);
- break;
- }
- }
- // 第三步:回复用,注意`msg.replyTo`。
- private void respClnt(Messenger clnt, int msgCode, Bundle data) {
- if (clnt == null) {
- return;
- }
- try {
- Message msg = Message.obtain(null, msgCode);
- msg.replyTo = mMessenger; // 绑定服务端信使
- if (data != null) {
- msg.setData(data);
- }
- clnt.send(msg); // 用客户端信使发消息
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- });
- @Override
- public IBinder onBind(Intent intent) {
- Log.e(TAG, "onBind");
- return mMessenger.getBinder();
- }
- // ......
- }
MessengerActivity
1)AndroidManifest.xml声明权限
- <uses-permission android:name="org.join.permission.SERVICE" />
2)MessengerActivity核心代码
1. 创建Messenger
- // 服务端的信使,后面会绑定
- private Messenger mService;
- // 第一步:新建
- final Messenger mMessenger = new Messenger(new Handler() {
- // 第二步:处理Message
- @Override
- public void dispatchMessage(Message msg) {
- switch (msg.what) {
- case SERV_RES_HAHA:
- String s = msg.getData().getString("msg");
- toast("HAHA! " + s);
- Bundle data = new Bundle();
- data.putString("msg", "I am you.");
- sendMsg(CLNT_REQ_SURPRISE, data);
- break;
- }
- }
- });
- // 第三步:回复用,同样注意`msg.replyTo`。
- private void sendMsg(int msgCode, Bundle data) {
- if (mService == null) {
- toast("Service is disconnected!");
- return;
- }
- try {
- Message msg = Message.obtain(null, msgCode);
- msg.replyTo = mMessenger; // 绑定客户端信使
- if (data != null) {
- msg.setData(data);
- }
- mService.send(msg); // 用服务端信使发消息
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
2. 绑定Service
- // 和一般绑定Service一样
- private ServiceConnection servConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mService = new Messenger(service); // 不过,这里改为Messenger
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- }
- };
- // 绑定方法
- protected void doBindService() {
- bindService(new Intent("org.join.service.MESSENGER"), servConnection, BIND_AUTO_CREATE);
- isBound = true;
- }
- // 解绑方法
- protected void doUnbindService() {
- if (isBound) {
- unbindService(servConnection);
- isBound = false;
- }
- }
好了,客户端要发送消息,调用sendMsg()就可以了。
AIDL
也挺简单的,恩,继续...
RemoteService
1)AndroidManifest.xml声明权限,就之前的,ok了。
2)注册RemoteService
- <service
- android:name="org.join.aidl.RemoteService"
- android:exported="true"
- android:permission="org.join.permission.SERVICE"
- android:process=":remote" >
- <intent-filter>
- <action android:name="org.join.service.AIDL" />
- </intent-filter>
- </service>
3)搞个parcelable对象
不能就用基本类型是不,所以要搞个对象^^。
恩,Event.java就是了。然后要为它写个aidl。
Event.aidl
- package org.join.aidl;
- parcelable Event;
简单吧。
4)然后弄个Callback
不能就单向通信是不,所以要用来回调客户端。
IRemoteCallback.aidl
- package org.join.aidl;
- import org.join.aidl.Event;
- /**
- * @brief 远程回调
- * @author join
- */
- interface IRemoteCallback {
- void onEvent(in Event event);
- }
4)服务的AIDL了
IRemoteService.aidl
- package org.join.aidl;
- import org.join.aidl.IRemoteCallback;
- import org.join.aidl.Event;
- /**
- * @brief 远程服务
- * @author join
- */
- interface IRemoteService {
- void registerCallback(in IRemoteCallback cb);
- void unregisterCallback(in IRemoteCallback cb);
- Event requestEvent();
- }
5)哦,总算到RemoteService了
RemoteService.java,恩,直接参考了ApiDemo,捂脸~
- public class RemoteService extends Service {
- static final String TAG = "RemoteService";
- public static final String ACTION = "org.join.service.AIDL";
- final RemoteCallbackList<IRemoteCallback> mCallbacks = new RemoteCallbackList<IRemoteCallback>();
- private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
- @Override
- public void registerCallback(IRemoteCallback cb) throws RemoteException {
- if (cb != null)
- mCallbacks.register(cb);
- }
- @Override
- public void unregisterCallback(IRemoteCallback cb) throws RemoteException {
- if (cb != null)
- mCallbacks.unregister(cb);
- }
- @Override
- public Event requestEvent() throws RemoteException {
- Event event = new Event();
- event.setId(Integer.MAX_VALUE);
- event.setName("Are you?");
- return event;
- }
- };
- private static final int REPORT_EVENT = 1;
- private final Handler mHandler = new Handler() {
- private Event event = new Event();
- private int count = 0;
- @Override
- public void dispatchMessage(Message msg) {
- switch (msg.what) {
- case REPORT_EVENT: {
- event.setId(count);
- event.setName("name" + count);
- count++;
- // Broadcast to all clients the new value.
- final int N = mCallbacks.beginBroadcast();
- for (int i = 0; i < N; i++) {
- try {
- mCallbacks.getBroadcastItem(i).onEvent(event);
- } catch (RemoteException e) {
- // The RemoteCallbackList will take care of removing the dead object for us.
- }
- }
- mCallbacks.finishBroadcast();
- // Repeat every 1 second.
- sendMessageDelayed(obtainMessage(REPORT_EVENT), 1 * 1000);
- }
- break;
- default:
- super.handleMessage(msg);
- }
- }
- };
- @Override
- public IBinder onBind(Intent intent) {
- Log.e(TAG, "onBind");
- return mBinder;
- }
- @Override
- public void onCreate() {
- Log.e(TAG, "onCreate");
- super.onCreate();
- mHandler.sendEmptyMessage(REPORT_EVENT);
- }
- @Override
- public void onDestroy() {
- Log.e(TAG, "onDestroy");
- super.onDestroy();
- mHandler.removeMessages(REPORT_EVENT);
- }
- // ......
- }
只要这个服务开启,每1秒回调下onEvent()。
至于RemoteCallbackList,是方便我们管理的,不然在RemoteException时,我们要亲自remote才行。
MessengerActivity
1)AndroidManifest.xml声明权限,也是之前的,ok了。
2)然后,之前辛苦工作的奖励时间^^
把Event.java、Event.aidl、IRemoteCallback.aidl、IRemoteService.aidl拷贝过来,开心吧。
3)还是MessengerActivity内绑定
1. 回调和请求
- // 远程服务,后面会绑定
- private IRemoteService mRemoteService = null;
- // 回调的实现,注意了吧,要用handler,之前也是。
- private IRemoteCallback mCallback = new IRemoteCallback.Stub() {
- @Override
- public void onEvent(Event event) throws RemoteException {
- mHandler.sendMessage(mHandler.obtainMessage(BUMP_EVENT, event));
- }
- };
- private static final int BUMP_EVENT = 1;
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case BUMP_EVENT:
- Event event = (Event) msg.obj;
- tvEvent.setText(event.toString());
- break;
- default:
- super.handleMessage(msg);
- }
- }
- };
- // 直接请求事件
- public void reqEvent(View v) {
- Event event = null;
- try {
- if (mRemoteService != null) {
- event = mRemoteService.requestEvent();
- }
- } catch (RemoteException e) {
- } finally {
- toast(event == null ? "Remote service is disconnected!" : event.toString());
- }
- }
2. 绑定Service
- // 同样是绑定Service的过程
- private ServiceConnection servRemoteConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- mRemoteService = IRemoteService.Stub.asInterface(service); // 这里,绑定的远程服务
- tvEvent.setText("Attached.");
- try {
- mRemoteService.registerCallback(mCallback); // 调用服务方法注册回调
- } catch (RemoteException e) {
- }
- }
- public void onServiceDisconnected(ComponentName className) {
- mRemoteService = null;
- btnServAidl.setChecked(false);
- tvEvent.setText("Disconnected.");
- }
- };
- protected void doBindRemoteService() {
- bindService(new Intent("org.join.service.AIDL"), servRemoteConnection, BIND_AUTO_CREATE);
- isRemoteBound = true;
- tvEvent.setText("Binding.");
- }
- protected void doUnbindRemoteService() {
- if (isRemoteBound) {
- unbindService(servRemoteConnection);
- isRemoteBound = false;
- }
- }
哦也,all done。
礼物
附赠两个小工程
`AndroidFragment`
- Fragment组件的例子。
- 主要注释,一些方法说明&注意点。
`AndroidJUnit`
- Run as -> Android JUnit test。
- 主要代码,src/test目录下。
附件:http://down.51cto.com/data/2362693
本文转自winorlose2000 51CTO博客,原文链接:http://blog.51cto.com/vaero/1188608,如需转载请自行联系原作者