很久沒用跨程序通信了,然後等自己又要用的時候,網上一搜,千遍一律,還很渣,吐血~
工程有兩份`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);
}
}
// 第三步:回複用,注意`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
2)MessengerActivity核心代碼
1. 建立Messenger
// 服務端的信使,後面會綁定
private Messenger mService;
// 第一步:建立
final Messenger mMessenger = new Messenger(new Handler() {
// 第二步:處理Message
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() {
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service); // 不過,這裡改為Messenger
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
android:name="org.join.aidl.RemoteService"
<action android:name="org.join.service.AIDL" />
3)搞個parcelable對象
不能就用基本類型是不,是以要搞個對象^^。
恩,Event.java就是了。然後要為它寫個aidl。
Event.aidl
package org.join.aidl;
parcelable Event;
簡單吧。
4)然後弄個Callback
不能就單向通信是不,是以要用來回調用戶端。
IRemoteCallback.aidl
import org.join.aidl.Event;
/**
* @brief 遠端回調
* @author join
*/
interface IRemoteCallback {
void onEvent(in Event event);
4)服務的AIDL了
IRemoteService.aidl
import org.join.aidl.IRemoteCallback;
* @brief 遠端服務
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() {
public void registerCallback(IRemoteCallback cb) throws RemoteException {
if (cb != null)
mCallbacks.register(cb);
public void unregisterCallback(IRemoteCallback cb) throws RemoteException {
mCallbacks.unregister(cb);
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;
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);
default:
super.handleMessage(msg);
return mBinder;
public void onCreate() {
Log.e(TAG, "onCreate");
super.onCreate();
mHandler.sendEmptyMessage(REPORT_EVENT);
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
mHandler.removeMessages(REPORT_EVENT);
隻要這個服務開啟,每1秒回調下onEvent()。
至于RemoteCallbackList,是友善我們管理的,不然在RemoteException時,我們要親自remote才行。
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() {
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() {
public void handleMessage(Message msg) {
case BUMP_EVENT:
Event event = (Event) msg.obj;
tvEvent.setText(event.toString());
default:
super.handleMessage(msg);
// 直接請求事件
public void reqEvent(View v) {
Event event = null;
if (mRemoteService != null) {
event = mRemoteService.requestEvent();
} finally {
toast(event == null ? "Remote service is disconnected!" : event.toString());
// 同樣是綁定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目錄下。
<a href="http://down.51cto.com/data/2362693" target="_blank">附件:http://down.51cto.com/data/2362693</a>
本文轉自winorlose2000 51CTO部落格,原文連結:http://blog.51cto.com/vaero/1188608,如需轉載請自行聯系原作者