AIDL使用

最近有空就在看IPC,正好路過AIDL這裏,發現基本忘乾淨了…正好藉此機會回顧並記錄下來,那麼接下來我就先擼爲敬了.

AIDL用來做什麼

AIDL(Android 接口定義語言)與您可能使用過的其他 IDL 類似。 您可以利用它定義客戶端與服務使用進程間通信 (IPC) 進行相互通信時都認可的編程接口。 在 Android 上,一個進程通常無法訪問另一個進程的內存。 儘管如此,進程需要將其對象分解成操作系統能夠識別的原語,並將對象編組成跨越邊界的對象。 編寫執行這一編組操作的代碼是一項繁瑣的工作,因此 Android 會使用 AIDL 來處理。

上面是文檔中的描述,通俗的說法:AIDL的作用是讓你可以在自己的APP裏綁定一個其他APP的service並可以拿到它暴露給你的方法獲取數據,這樣你的APP可以和其他APP交互。

AIDL使用

上面已經說過AIDL是用來將對象分解成操作系統能夠識別的原語,並將對象編組成跨越邊界的對象,那麼這裏就按AIDL中可以使用的數據類型來分別說明如何使用.

基本類型

因爲AIDL是兩個APP交互啦,所以當然要兩個APP啦,我們在第一個工程目錄右鍵

輸入名字AS就幫我們新建了AIDL文件了

// IMyName.aidl
package com.zly.www.test1;

// Declare any non-default types here with import statements

interface IMyName {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

這裏basicTypes這個方法其實沒啥用可以刪掉,但從他註釋裏面可以看出,AIDL默認支持int,long,boolean,float,double,String基本類型的數據.因爲這裏是要跨進程通訊的,所以不是隨便你自己定義的一個類型就可以在AIDL使用的,自定義類型我們在後面會講.我們在AIDL文件中定義一個我們要提供給第二個APP使用的接口.

那麼我們把這個類稍微修改下

// IMyName.aidl
package com.zly.www.test1;

// Declare any non-default types here with import statements

interface IMyName {

    String getName();

}

然後點下sycn project讓AS幫我們生成下aidl代碼.

接下來我們新建一個service並且在清單註冊,然後在service中新建一個內部類MyBinder繼承剛剛寫的AIDL接口IMyName裏的Stub類並實現方法,在onBind()返回該實例,你可能會問我沒在IMyName裏寫Stub類呀,其實這裏Stub是AS根據剛剛AIDL文件生成的代碼中的.

public class MyService extends Service {

    private MyBinder mBinder = new MyBinder();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    class MyBinder extends IMyName.Stub{

        @Override
        public String getName() throws RemoteException {
            return "帥也是錯嗎";
        }
    }
}

接下來新建一個項目,將前面寫的AIDL文件拷貝過來,要注意的是包名必須完全一致.

syncProject一下項目,然後在MainActivity中綁定service

public class MainActivity extends AppCompatActivity {

    private IMyName iMyName;
    private ServiceConnection serviceConnection;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent("aaaa");
        intent.setPackage("com.zly.www.test1");
        bindService(intent, serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iMyName = IMyName.Stub.asInterface(service);
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                iMyName = null;
            }
        }, BIND_AUTO_CREATE);

    }

    public void get(View v) {
        try {
            Toast.makeText(this, iMyName.getName(), Toast.LENGTH_SHORT).show();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }
}

這邊我們通過隱式意圖來綁定service,在onServiceConnected方法中通過IMyName.Stub.asInterface(service)獲取IMyName對象,然後在get()中調用IMyName.getName()。(這裏有點需要注意Android 5.0出後,其中有個特性就是Service Intent must be explitict,也就是說從Lollipop開始,service服務必須採用顯示方式啓動,所以這裏intent我指定了package)

自定義類型

如果要在AIDL中使用自定義類型的數據,第一自定義類型要實現Parcelable接口,第二需要寫一個ADIL聲明文件.

下面創建一個Student類實現Parcelable接口

public class Student implements Parcelable {

    public Student(String name) {
        this.name = name;
    }

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    protected Student(Parcel in) {
        name = in.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<Student> CREATOR = new Creator<Student>() {
        @Override
        public Student createFromParcel(Parcel in) {
            return new Student(in);
        }

        @Override
        public Student[] newArray(int size) {
            return new Student[size];
        }
    };

}

接下來新建一個aidl文件,名稱爲我們自定義類型的名稱,這邊是Student.aidl。在Student.aidl申明我們的自定義類型和它的完整包名,注意這邊parcelable是小寫的,不是Parcelable接口,一個自定類型需要一個這樣同名的AIDL文件來聲明。

package com.zly.www.test1;
parcelable Student;

然後在我們的aidl接口中導入自定義數據類型

syncProjcet,然後在service中實現接口方法

class MyBinder extends IMyName.Stub{

        @Override
        public String getName() throws RemoteException {
            return "帥也是錯嗎";
        }

        @Override
        public Student getStudent() throws RemoteException {
            return new Student("朱利源");
        }
    }

然後把AIDL文件與自定義類型文件拷到第二個項目,注意這裏還是包名一致

接下來就可以在該activity中使用自定義類型的數據了

public class MainActivity extends AppCompatActivity {
    //.....
    public void get(View v) {
        try {
            Toast.makeText(this, iMyName.getStudent().getName(), Toast.LENGTH_SHORT).show();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

}

效果如下

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章