天天看點

Android Service Messenger & AIDL 的跨程序通信例子

很久沒用跨程序通信了,然後等自己又要用的時候,網上一搜,千遍一律,還很渣,吐血~

工程有兩份`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,如需轉載請自行聯系原作者

繼續閱讀