很久没用跨进程通信了,然后等自己又要用的时候,网上一搜,千遍一律,还很渣,吐血~

工程有两份`MessengerService`&`MessengerActivity`,前个提供服务,后个访问服务。


跨进程通信

就多个apk互相通信,当然广播也是不错的。不过这里用的是Messenger和AIDL,并且都弄成双向的了。


Messenger

信使,底层说是也用的AIDL。用起来挺方便的。


MessengerService

1)AndroidManifest.xml声明权限

 
  
  1. <permission 
  2.     android:name="org.join.permission.SERVICE" 
  3.     android:protectionLevel="normal" > 
  4. </permission> 
  5.  
  6. <uses-permission android:name="org.join.permission.SERVICE" /> 

为什么弄个带权限的呢?因为讨厌任何警告==。

2)注册MessengerService

 
  
  1. <service 
  2.     android:name="org.join.messenger.MessengerService" 
  3.     android:exported="true" 
  4.     android:permission="org.join.permission.SERVICE" 
  5.     android:process=":remote" > 
  6.     <intent-filter> 
  7.         <action android:name="org.join.service.MESSENGER" /> 
  8.     </intent-filter> 
  9. </service> 

这里把权限加上了,不然最新ADT是会有个警告的。就一嘀咕的老头,讨人厌。

3)MessengerService核心代码

 
  
  1. public class MessengerService extends Service implements MessageCode { 
  2.  
  3.     static final String TAG = "MessengerService"
  4.  
  5.     public static final String ACTION = "org.join.service.MESSENGER"
  6.  
  7.     // 第一步:新建 
  8.     final Messenger mMessenger = new Messenger(new Handler() { 
  9.  
  10.         // 第二步:处理Message 
  11.         @Override 
  12.         public void dispatchMessage(Message msg) { 
  13.             switch (msg.what) { 
  14.             case CLNT_REQ_HELLO: 
  15.                 toast("Hello!"); 
  16.                 Bundle data = new Bundle(); 
  17.                 data.putString("msg""Who am I?"); 
  18.                 // 这个`msg.replyTo`是客户端的信使 
  19.                 respClnt(msg.replyTo, SERV_RES_HAHA, data); 
  20.                 break
  21.             case CLNT_REQ_SURPRISE: 
  22.                 String s = msg.getData().getString("msg"); 
  23.                 toast("Surprise! " + s); 
  24.                 break
  25.             } 
  26.         } 
  27.  
  28.         // 第三步:回复用,注意`msg.replyTo`。 
  29.         private void respClnt(Messenger clnt, int msgCode, Bundle data) { 
  30.             if (clnt == null) { 
  31.                 return
  32.             } 
  33.             try { 
  34.                 Message msg = Message.obtain(null, msgCode); 
  35.                 msg.replyTo = mMessenger; // 绑定服务端信使 
  36.                 if (data != null) { 
  37.                     msg.setData(data); 
  38.                 } 
  39.                 clnt.send(msg); // 用客户端信使发消息 
  40.             } catch (RemoteException e) { 
  41.                 e.printStackTrace(); 
  42.             } 
  43.         } 
  44.     }); 
  45.  
  46.     @Override 
  47.     public IBinder onBind(Intent intent) { 
  48.         Log.e(TAG, "onBind"); 
  49.         return mMessenger.getBinder(); 
  50.     } 
  51.  
  52.     // ...... 
  53.  


MessengerActivity

1)AndroidManifest.xml声明权限

 
  
  1. <uses-permission android:name="org.join.permission.SERVICE" /> 

2)MessengerActivity核心代码

1. 创建Messenger

 
  
  1. // 服务端的信使,后面会绑定 
  2. private Messenger mService; 
  3.  
  4. // 第一步:新建 
  5. final Messenger mMessenger = new Messenger(new Handler() { 
  6.  
  7.     // 第二步:处理Message 
  8.     @Override 
  9.     public void dispatchMessage(Message msg) { 
  10.         switch (msg.what) { 
  11.         case SERV_RES_HAHA: 
  12.             String s = msg.getData().getString("msg"); 
  13.             toast("HAHA! " + s); 
  14.             Bundle data = new Bundle(); 
  15.             data.putString("msg""I am you."); 
  16.             sendMsg(CLNT_REQ_SURPRISE, data); 
  17.             break
  18.         } 
  19.     } 
  20. }); 
  21.  
  22. // 第三步:回复用,同样注意`msg.replyTo`。 
  23. private void sendMsg(int msgCode, Bundle data) { 
  24.     if (mService == null) { 
  25.         toast("Service is disconnected!"); 
  26.         return
  27.     } 
  28.     try { 
  29.         Message msg = Message.obtain(null, msgCode); 
  30.         msg.replyTo = mMessenger; // 绑定客户端信使 
  31.         if (data != null) { 
  32.             msg.setData(data); 
  33.         } 
  34.         mService.send(msg); // 用服务端信使发消息 
  35.     } catch (RemoteException e) { 
  36.         e.printStackTrace(); 
  37.     } 

2. 绑定Service

 
  
  1. // 和一般绑定Service一样 
  2. private ServiceConnection servConnection = new ServiceConnection() { 
  3.  
  4.     @Override 
  5.     public void onServiceConnected(ComponentName name, IBinder service) { 
  6.         mService = new Messenger(service); // 不过,这里改为Messenger 
  7.     } 
  8.  
  9.     @Override 
  10.     public void onServiceDisconnected(ComponentName name) { 
  11.         mService = null
  12.     } 
  13. }; 
  14.  
  15. // 绑定方法 
  16. protected void doBindService() { 
  17.     bindService(new Intent("org.join.service.MESSENGER"), servConnection, BIND_AUTO_CREATE); 
  18.     isBound = true
  19.  
  20. // 解绑方法 
  21. protected void doUnbindService() { 
  22.     if (isBound) { 
  23.         unbindService(servConnection); 
  24.         isBound = false
  25.     } 

好了,客户端要发送消息,调用sendMsg()就可以了。


AIDL

也挺简单的,恩,继续...


RemoteService

1)AndroidManifest.xml声明权限,就之前的,ok了。

2)注册RemoteService

 
  
  1. <service 
  2.     android:name="org.join.aidl.RemoteService" 
  3.     android:exported="true" 
  4.     android:permission="org.join.permission.SERVICE" 
  5.     android:process=":remote" > 
  6.     <intent-filter> 
  7.         <action android:name="org.join.service.AIDL" /> 
  8.     </intent-filter> 
  9. </service> 

3)搞个parcelable对象

不能就用基本类型是不,所以要搞个对象^^。

恩,Event.java就是了。然后要为它写个aidl。

Event.aidl

 
  
  1. package org.join.aidl; 
  2.  
  3. parcelable Event; 

简单吧。

4)然后弄个Callback

不能就单向通信是不,所以要用来回调客户端。

IRemoteCallback.aidl

 
  
  1. package org.join.aidl; 
  2.  
  3. import org.join.aidl.Event; 
  4.  
  5. /** 
  6.  * @brief 远程回调 
  7.  * @author join 
  8.  */ 
  9. interface IRemoteCallback { 
  10.  
  11.     void onEvent(in Event event); 
  12.  

4)服务的AIDL了

IRemoteService.aidl

 
  
  1. package org.join.aidl; 
  2.  
  3. import org.join.aidl.IRemoteCallback; 
  4. import org.join.aidl.Event; 
  5.  
  6. /** 
  7.  * @brief 远程服务 
  8.  * @author join 
  9.  */ 
  10. interface IRemoteService { 
  11.  
  12.     void registerCallback(in IRemoteCallback cb); 
  13.  
  14.     void unregisterCallback(in IRemoteCallback cb); 
  15.  
  16.     Event requestEvent(); 
  17.  

5)哦,总算到RemoteService了

RemoteService.java,恩,直接参考了ApiDemo,捂脸~

 
  
  1. public class RemoteService extends Service { 
  2.  
  3.     static final String TAG = "RemoteService"
  4.  
  5.     public static final String ACTION = "org.join.service.AIDL"
  6.  
  7.     final RemoteCallbackList<IRemoteCallback> mCallbacks = new RemoteCallbackList<IRemoteCallback>(); 
  8.  
  9.     private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { 
  10.  
  11.         @Override 
  12.         public void registerCallback(IRemoteCallback cb) throws RemoteException { 
  13.             if (cb != null
  14.                 mCallbacks.register(cb); 
  15.         } 
  16.  
  17.         @Override 
  18.         public void unregisterCallback(IRemoteCallback cb) throws RemoteException { 
  19.             if (cb != null
  20.                 mCallbacks.unregister(cb); 
  21.         } 
  22.  
  23.         @Override 
  24.         public Event requestEvent() throws RemoteException { 
  25.             Event event = new Event(); 
  26.             event.setId(Integer.MAX_VALUE); 
  27.             event.setName("Are you?"); 
  28.             return event; 
  29.         } 
  30.     }; 
  31.  
  32.     private static final int REPORT_EVENT = 1
  33.  
  34.     private final Handler mHandler = new Handler() { 
  35.  
  36.         private Event event = new Event(); 
  37.         private int count = 0
  38.  
  39.         @Override 
  40.         public void dispatchMessage(Message msg) { 
  41.             switch (msg.what) { 
  42.             case REPORT_EVENT: { 
  43.                 event.setId(count); 
  44.                 event.setName("name" + count); 
  45.                 count++; 
  46.  
  47.                 // Broadcast to all clients the new value. 
  48.                 final int N = mCallbacks.beginBroadcast(); 
  49.                 for (int i = 0; i < N; i++) { 
  50.                     try { 
  51.                         mCallbacks.getBroadcastItem(i).onEvent(event); 
  52.                     } catch (RemoteException e) { 
  53.                         // The RemoteCallbackList will take care of removing the dead object for us. 
  54.                     } 
  55.                 } 
  56.                 mCallbacks.finishBroadcast(); 
  57.  
  58.                 // Repeat every 1 second. 
  59.                 sendMessageDelayed(obtainMessage(REPORT_EVENT), 1 * 1000); 
  60.             } 
  61.                 break
  62.             default
  63.                 super.handleMessage(msg); 
  64.             } 
  65.         } 
  66.     }; 
  67.  
  68.     @Override 
  69.     public IBinder onBind(Intent intent) { 
  70.         Log.e(TAG, "onBind"); 
  71.         return mBinder; 
  72.     } 
  73.  
  74.     @Override 
  75.     public void onCreate() { 
  76.         Log.e(TAG, "onCreate"); 
  77.         super.onCreate(); 
  78.         mHandler.sendEmptyMessage(REPORT_EVENT); 
  79.     } 
  80.  
  81.     @Override 
  82.     public void onDestroy() { 
  83.         Log.e(TAG, "onDestroy"); 
  84.         super.onDestroy(); 
  85.         mHandler.removeMessages(REPORT_EVENT); 
  86.     } 
  87.  
  88.     // ...... 
  89.  

只要这个服务开启,每1秒回调下onEvent()。

至于RemoteCallbackList,是方便我们管理的,不然在RemoteException时,我们要亲自remote才行。


MessengerActivity

1)AndroidManifest.xml声明权限,也是之前的,ok了。

2)然后,之前辛苦工作的奖励时间^^

Event.javaEvent.aidlIRemoteCallback.aidlIRemoteService.aidl拷贝过来,开心吧。

3)还是MessengerActivity内绑定

1. 回调和请求

 
  
  1. // 远程服务,后面会绑定 
  2. private IRemoteService mRemoteService = null
  3.  
  4. // 回调的实现,注意了吧,要用handler,之前也是。 
  5. private IRemoteCallback mCallback = new IRemoteCallback.Stub() { 
  6.     @Override 
  7.     public void onEvent(Event event) throws RemoteException { 
  8.         mHandler.sendMessage(mHandler.obtainMessage(BUMP_EVENT, event)); 
  9.     } 
  10. }; 
  11.  
  12. private static final int BUMP_EVENT = 1
  13.  
  14. private Handler mHandler = new Handler() { 
  15.     @Override 
  16.     public void handleMessage(Message msg) { 
  17.         switch (msg.what) { 
  18.         case BUMP_EVENT: 
  19.             Event event = (Event) msg.obj; 
  20.             tvEvent.setText(event.toString()); 
  21.             break
  22.         default
  23.             super.handleMessage(msg); 
  24.         } 
  25.     } 
  26.  
  27. }; 
  28.  
  29. // 直接请求事件 
  30. public void reqEvent(View v) { 
  31.     Event event = null
  32.     try { 
  33.         if (mRemoteService != null) { 
  34.             event = mRemoteService.requestEvent(); 
  35.         } 
  36.     } catch (RemoteException e) { 
  37.     } finally { 
  38.         toast(event == null ? "Remote service is disconnected!" : event.toString()); 
  39.     } 

2. 绑定Service

 
  
  1. // 同样是绑定Service的过程 
  2. private ServiceConnection servRemoteConnection = new ServiceConnection() { 
  3.     public void onServiceConnected(ComponentName className, IBinder service) { 
  4.         mRemoteService = IRemoteService.Stub.asInterface(service); // 这里,绑定的远程服务 
  5.         tvEvent.setText("Attached."); 
  6.         try { 
  7.             mRemoteService.registerCallback(mCallback); // 调用服务方法注册回调 
  8.         } catch (RemoteException e) { 
  9.         } 
  10.     } 
  11.  
  12.     public void onServiceDisconnected(ComponentName className) { 
  13.         mRemoteService = null
  14.         btnServAidl.setChecked(false); 
  15.         tvEvent.setText("Disconnected."); 
  16.     } 
  17. }; 
  18.  
  19. protected void doBindRemoteService() { 
  20.     bindService(new Intent("org.join.service.AIDL"), servRemoteConnection, BIND_AUTO_CREATE); 
  21.     isRemoteBound = true
  22.     tvEvent.setText("Binding."); 
  23.  
  24. protected void doUnbindRemoteService() { 
  25.     if (isRemoteBound) { 
  26.         unbindService(servRemoteConnection); 
  27.         isRemoteBound = false
  28.     } 

哦也,all done。


礼物

附赠两个小工程

`AndroidFragment`

  • Fragment组件的例子。
  • 主要注释,一些方法说明&注意点。

`AndroidJUnit`

  • Run as -> Android JUnit test。
  • 主要代码,src/test目录下。