android: 使用AIDL實現處理序間通訊(附樣本源碼下載)

來源:互聯網
上載者:User

關於AIDL的介紹及實現步驟等請參考:

http://www.cnblogs.com/hibraincol/archive/2011/09/06/2169325.html

本篇文章只是用一個執行個體來分析AIDL的實現。

本樣本實現的是:AIDL用戶端通過AIDL介面擷取AIDL服務端中提供的webPage資訊,下面詳述AIDL通訊的實現步驟:

一、編寫服務端代碼

1. 首先編寫AndroidManifest.xml檔案:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"      package="com.braincol.aidl.service"      android:versionCode="1"      android:versionName="1.0">    <uses-sdk android:minSdkVersion="8" />    <application android:icon="@drawable/icon" android:label="@string/app_name">    <service android:name="RemoteService">        <intent-filter>            <action android:name="com.braincol.aidl.remote.webpage"/>        </intent-filter>    </service>    </application></manifest>

 

可以看到服務端的包名為:com.braincol.aidl.service,且該服務端只需一個service組件提供AIDL服務,service組件的名稱為RemoteService,這是待會要實現的Service子類。其中<action android:name="com.braincol.aidl.remote.webpage"/> ,指定了action名稱為"com.braincol.aidl.remote.webpage", 用戶端會通過該action的名稱來找到並串連該服務端。

2. 建立RemoteWebPage.aidl檔案

在包com.braincol.aidl.service下建立RemoteWebPage.aidl檔案:

package com.braincol.aidl.service; interface RemoteWebPage {    String getCurrentPageUrl();     }

可以看到內容很簡單,該檔案中包含一個RemoteWebPage 介面,並且介面中只有getCurrentPageUrl()這麼一個方法,後面的用戶端將通過這裡提供的getCurrentPageUrl()方法擷取想要的資訊。

3.產生RemoteWebPage.java檔案

儲存並編譯該工程(在eclipse中編譯)會看到 gen/ 目錄下的com.braincol.aidl.service包下出現了一個RemoteWebPage.java檔案:

/* * This file is auto-generated.  DO NOT MODIFY. * Original file: F:\\workspace\\android\\AIDL-simple\\AIDLService\\src\\com\\braincol\\aidl\\service\\RemoteWebPage.aidl */package com.braincol.aidl.service;public interface RemoteWebPage extends android.os.IInterface{    /** Local-side IPC implementation stub class. */    public static abstract class Stub extends android.os.Binder implements com.braincol.aidl.service.RemoteWebPage    {        private static final java.lang.String DESCRIPTOR = "com.braincol.aidl.service.RemoteWebPage";        /** Construct the stub at attach it to the interface. */        public Stub()        {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.braincol.aidl.service.RemoteWebPage interface,         * generating a proxy if needed.         */        public static com.braincol.aidl.service.RemoteWebPage asInterface(android.os.IBinder obj)        {            if ((obj==null)) {                return null;            }            android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);            if (((iin!=null)&&(iin instanceof com.braincol.aidl.service.RemoteWebPage))) {                return ((com.braincol.aidl.service.RemoteWebPage)iin);            }            return new com.braincol.aidl.service.RemoteWebPage.Stub.Proxy(obj);        }        public android.os.IBinder asBinder()        {            return this;        }        @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException        {            switch (code)            {            case INTERFACE_TRANSACTION:            {                reply.writeString(DESCRIPTOR);                return true;            }            case TRANSACTION_getCurrentPageUrl:            {                data.enforceInterface(DESCRIPTOR);                java.lang.String _result = this.getCurrentPageUrl();                reply.writeNoException();                reply.writeString(_result);                return true;            }            }            return super.onTransact(code, data, reply, flags);        }        private static class Proxy implements com.braincol.aidl.service.RemoteWebPage        {            private android.os.IBinder mRemote;            Proxy(android.os.IBinder remote)            {                mRemote = remote;            }            public android.os.IBinder asBinder()            {                return mRemote;            }            public java.lang.String getInterfaceDescriptor()            {                return DESCRIPTOR;            }            public java.lang.String getCurrentPageUrl() throws android.os.RemoteException            {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                java.lang.String _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getCurrentPageUrl, _data, _reply, 0);                    _reply.readException();                    _result = _reply.readString();                }                finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }        }        static final int TRANSACTION_getCurrentPageUrl = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);    }    public java.lang.String getCurrentPageUrl() throws android.os.RemoteException;}

這個檔案是Android SDK工具根據RemoteWebPage.aidl自動產生的,不要嘗試著去修改該檔案(改了也白改)。可以看到RemoteWebPage介面內包含了一個名為Stub的抽象的內部類,該類聲明了RemoteWebPage.aidl中描述的方法getCurrentPageUrl(),並且還定義了少量的輔助方法Stub還定義了少量的輔助方法,尤其是asInterface(),通過它或以獲得IBinder(當applicationContext.bindService()成功調用時傳遞到用戶端的onServiceConnected())並且返回用於調用IPC方法的介面執行個體,更多細節參見Calling an IPC Method

4. 編寫RemoteService.java

為了實現AIDL通訊,必須在RemoteService類中實現RemoteWebPage.Stub介面,然後RemoteWebPage.Stbu內的相關方法,下面是RemoteService.java的代碼:

package com.braincol.aidl.service;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;/** *  * @author briancol * @description 提供service * */public class RemoteService extends Service {    private final static String TAG = "RemoteService";    @Override    public IBinder onBind(Intent intent) {        Log.i(TAG, "OnBind");        return new MyBinder();    }    private class MyBinder extends RemoteWebPage.Stub{        @Override        public String getCurrentPageUrl() throws RemoteException{            return "http://www.cnblogs.com/hibraincol/";        }    }}

這樣MyBinder就是一個RemoteWebPage.Stub類得子類,這樣就可以通過RemoteService向用戶端暴露AIDL介面了(MyBinder )。現在,如果用戶端(比如一個Activity)調用bindService()來串連該服務端(RemoteService) ,用戶端的onServiceConnected()回呼函數將會獲得從服務端(RemoteService )的onBind()返回的MyBinder對象。

在這裡總結下服務端的編寫流程:

    1. 建立.aidl檔案:

        該檔案(YourInterface.aidl)定義了用戶端可用的方法和資料的介面

    2. 實現這個介面:

        Android SDK將會根據你的.aidl檔案產生AIDL介面。產生的介面包含一個名為Stub的抽象內部類,該類聲明了所有.aidl中描述的方法,你必須在代碼裡繼承該Stub類並且實現.aidl中定義的方法。

    3.向用戶端公開服務端的介面:

        實現一個Service,並且在onBinder方法中返回第2步中實現的那個Stub類的子類(實作類別)。

 

至此,服務端的代碼就編寫完成了。 下面開始編寫用戶端。

二、編寫用戶端代碼

因為用戶端和服務端不在同一個進程(應用程式)中,那麼用戶端也必須在src/目錄下擁有和服務端同樣的一份.aidl檔案的拷貝(這樣的同樣是指:包名、類名、內容完全一樣,可以把用戶端的.aidl檔案理解為代理),這樣用戶端將會通過這個RemoteWebPage.aidl檔案在gen/目下產生和服務端一樣的RemoteWebPage.java檔案,然後用戶端就可以通過該介面來訪問服務端提供的方法了。下面是用戶端的只要代碼:

package com.braincol.aidl.client;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;import com.braincol.aidl.service.RemoteWebPage;public class ClientActivity extends Activity implements OnClickListener {    private final static String TAG="ClientActivity";    TextView textView ;    Button btn_bind ;    Button btn_getAllInfo;    String actionName = "com.braincol.aidl.remote.webpage";    RemoteWebPage remoteWebPage=null;    String allInfo = null;    boolean isBinded=false;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        textView = (TextView) findViewById(R.id.textView);        btn_bind = (Button) findViewById(R.id.btn_bind);        btn_getAllInfo = (Button)findViewById(R.id.btn_allinfo);        btn_getAllInfo.setEnabled(false);        btn_bind.setOnClickListener(this);        btn_getAllInfo.setOnClickListener(this);    }    @Override    protected void onPause(){        super.onPause();        Log.d(TAG,"onPause");        if(isBinded){            Log.d(TAG,"unbind");            unbindService(connection);            }    }    private class MyServiceConnection implements ServiceConnection{        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            Log.i(TAG, "建立串連...");            remoteWebPage = RemoteWebPage.Stub.asInterface(service);            if(remoteWebPage==null){                textView.setText("bind service failed!");                    return;            }            try {                isBinded=true;                btn_bind.setText("斷開");                textView.setText("已串連!");                allInfo = remoteWebPage.getCurrentPageUrl();                btn_getAllInfo.setEnabled(true);                } catch (RemoteException e) {                e.printStackTrace();            }        }        @Override        public void onServiceDisconnected(ComponentName name) {            Log.i(TAG, "onServiceDisconnected...");        }    }    MyServiceConnection connection = new MyServiceConnection();    @Override    public void onClick(View v) {        if(v==this.btn_bind){            if(!isBinded){                Intent intent  = new Intent(actionName);                bindService(intent, connection, Context.BIND_AUTO_CREATE);                            }else{                Log.i(TAG, "中斷連線...");                unbindService(connection);                btn_getAllInfo.setEnabled(false);                    btn_bind.setText("串連");                isBinded = false;                textView.setText("已中斷連線!");            }        }else if(v==this.btn_getAllInfo){            textView.setText(allInfo);        }    }}

 

上面的代碼中類MyServiceConnection實現了ServiceConnection類,在MyServiceConnection類的onServiceConnected方法中通過RemoteWebPage.Stub.asInterface(service)擷取到遠端服務端的RemoteWebPage介面對象remoteWebPage,這樣就可以通過remoteWebPage.getCurrentPageUrl()擷取到服務端提供的相關的資訊。用戶端通過bindService()方法綁定遠程服務端,通過unbindService()中斷連線。串連用戶端的相關的代碼為:

    Intent intent  = new Intent(actionName);    bindService(intent, connection, Context.BIND_AUTO_CREATE);

用戶端就是通過actionName(com.braincol.aidl.remote.webpage)來找到服務端。

下面總結下用戶端的編寫流程:

    1. 在 src/ 目錄下包含.adil檔案。

    2. 聲明一個IBinder介面(通過.aidl檔案產生的)的執行個體。

    3. 實現ServiceConnection.

    4. 調用Context.bindService()綁定你的ServiceConnection實作類別的對象(也就是遠程服務端)。

    5. 在onServiceConnected()方法中會接收到IBinder對象(也就是服務端),調用YourInterfaceName.Stub.asInterface((IBinder)service)將傳回值轉換為YourInterface類型。

    6. 調用介面中定義的方法,並且應該總是捕獲串連被打斷時拋出的DeadObjectException異常,這是遠端方法可能會拋出唯一異常。

    7. 調用Context.unbindService()方法中斷連線。

 

下面給出本樣本源碼的:

http://download.csdn.net/detail/Niosm/3593187

在附一個稍微複雜點的例子(通過IPC傳遞Parcelable對象):

http://download.csdn.net/detail/Niosm/3593376

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.