1. 程式人生 > >Android開發之AIDL實現遠端服務程序通訊(IPC)

Android開發之AIDL實現遠端服務程序通訊(IPC)

首先什麼是AIDL呢,它是Android系統中的一種介面定義語言,用於約束兩個程序間的通訊規則,供編譯器生成程式碼。
實現Android裝置上的兩個程序間通訊(IPC),程序之間的通訊資訊首先會被轉換成AIDL協議資訊,然後傳送給對方;對方接收到AIDL協議資訊後再轉換成相應的物件,由於程序之間的通訊資訊需要雙向的轉換,Android系統採用代理類在背後實現了資訊的雙向轉換,代理類是由Android編譯器生成,對於開發人員來數是透明個。

兩個程序間也就是應用間的通訊,一個是訪問者A應用 client另一個則是B應用的service,A要想訪問B的service是不可能直接的去呼叫B的方法的,但是如果要實現AIDL規則的話,則可以間接的訪問。這就類似於在開發webA應用的時候我們的應用要獲取另一個webB應用的資料,但是我們不知道webB應用在哪裡,但是如果WebB給給我提供一個WSDL檔案,我們就可以通過webservice去訪問應用中的方法,其實就是一個道理只是系統的不同。

首先我們來介紹下整個過程
這裡寫圖片描述
A應用請求B應用的 service ,如果A應用與B應用的 service綁定了以後那麼 B應用就會返回一個Binder ,A應用可以拿著這個Binder 去呼叫 B應用service中的方法。但是這個Binder 這是一個代理。

接下來我們看一下具體的程式碼:

我們先來配置一下B應用的 service
這裡寫圖片描述
建立一個QueryPerson.aidl檔案,這時候編譯器會自動的給我們在gen下相同的包生成一個java檔案。

package com.my.aidl;
//aidl的語法和我們定義介面很是類似,但是aidl不可以有任何的修飾符
interface
QueryPerson {
String query(int num); }

接下來建立service

public class QuerypersonService extends Service {

    private IBinder iBinder = new QuerypersonBinder();

    @Override
    public IBinder onBind(Intent intent) {

        return iBinder;
    }

    /**
     * 這個方法裡我們就不能再繼承IBinder了, 因為我們要讓這個service具有遠端通訊的能力
     * 
     * 所以這我們要繼承剛才系統幫我們生成的aidl 類
     * 
     * 這個方法繼承的是系統的android.os.Binder
     * public static abstract class Stub extends android.os.Binder
     * 
     */
private final class QuerypersonBinder extends QueryPerson.Stub{ //這裡就簡單的放一些資料測試 @Override public String queryPerson(int num) throws RemoteException { String[] names = new String[]{"張三","李四","王五","z趙六"}; String name = names[num]; return name; } } }

最後別忘了在AndroidMainifest.xml配置service

 <service android:name=".QuerypersonService" >
            <intent-filter>
                <action android:name="com.my.aidlservice" />
            </intent-filter>
 </service>

到這我們的service端的就寫完了

接下來A應用的程式碼
同樣的必須將service中的aidl檔案複製到A應用中
這裡寫圖片描述

配置activity程式碼:

public class MainActivity extends Activity {

    private EditText mEditText;
    private TextView mText;

    private PersonServiceConnection conn = new PersonServiceConnection();

    private QueryPerson queryPerson;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mText = (TextView) findViewById(R.id.Text);
        mEditText = (EditText) findViewById(R.id.content);

        // 採用隱世的intent 去啟動service
        Intent service = new Intent("com.my.aidlservice");
        // 繫結service
        bindService(service, conn, BIND_AUTO_CREATE);
    }
    //按鈕的點選事件
    public void QueryPerson(View v) {

        String number = mEditText.getText().toString();

        int num = Integer.parseInt(number);

        try {
            String name = queryPerson.queryPerson(num);
            mText.setText(name);

        } catch (RemoteException e) {
            e.printStackTrace();
        }

    }

    // 建立一個ServiceConnection
    private final class PersonServiceConnection implements ServiceConnection {
        // 當service繫結時
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //service 返回的IBinder 必須要進行轉換才可以使用,用asInterface()方法就可以轉換
            queryPerson = QueryPerson.Stub.asInterface(service);
        }
        // 當service撤銷繫結時
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }

    // 當activity銷燬時 會取消繫結service
    @Override
    protected void onDestroy() {

        unbindService(conn);
        super.onDestroy();
    }

}

佈局檔案:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

   <EditText
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="QueryPerson"
        android:text="Click"/>


    <TextView
        android:id="@+id/Text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

實際的效果就是下圖所示的:
這裡寫圖片描述

這就是簡單的遠端服務程序間通訊,很簡答吧!

之前想過不同應用之間為啥不直接用contentprovider呢 ,因為contentprovider只是向呼叫者暴露了你的資料庫而已,而且還不是實時的資料;但是用AIDL的話可是實時去訪問其他應用的資料。