Android AIDL 學習記錄

AIDL全程爲 Android Interface Definition Language 即 android接口定義語言  能夠進行進程間的通訊

通訊時默認支持的數據類型如下:

(1)Java中的八種基本數據類型,包括 byte,short,int,long,float,double,boolean,char。

(2)String 類型和CharSequence類型。

(3)List類型:List中的所有元素必須是AIDL支持的類型之一,或者是一個其他AIDL生成的接口,或者是由parcelable進行序列化的對象。List可以使用泛型。

(4)Map類型:Map中的所有元素和list所支持的一致,但是Map是不支持泛型的。

使用AIDL也可以傳遞對象,但是對象必須經過parcelable進行序列化纔可以使用,序列化形式如下:

public class Bean_Data implements Parcelable {
    private String data;

    public Bean_Data(){

    }

    protected Bean_Data(Parcel in) {
        data = in.readString();
    }

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

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

    public String getData() {
        //如果是String類型,那麼判斷是否爲空,爲空返回"",否則返回字段值本身
        return data == null ? "" : data;
    }

    public void setData(String data) {
        this.data = data;
    }


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

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(data);
    }
    /**
     * 參數是一個Parcel,用它來存儲與傳輸數據
     * @param dest
     */
    public void readFromParcel(Parcel dest) {
        //注意,此處的讀值順序應當是和writeToParcel()方法中一致的
        data = dest.readString();
    }

}

readFromParcel方法爲人爲記性添加,其餘方法除get和set方法外都可以通過編譯器進行自動添加

傳遞序列化的對象時 應在定義接口方法的時候使用定向tag,定向tag的使用方法如下:

AIDL中的定向 tag 表示了在跨進程通信中數據的流向,其中 in 表示數據只能由客戶端流向服務端, out 表示數據只能由服務端流向客戶端,而 inout 則表示數據可在服務端與客戶端之間雙向流通。其中,數據流向是針對在客戶端中的那個傳入方法的對象而言的。in 爲定向 tag 的話表現爲服務端將會接收到一個那個對象的完整數據,但是客戶端的那個對象不會因爲服務端對傳參的修改而發生變動;out 的話表現爲服務端將會接收到那個對象的的空對象,但是在服務端對接收到的空對象有任何修改之後客戶端將會同步變動;inout 爲定向 tag 的情況下,服務端將會接收到客戶端傳來對象的完整信息,並且客戶端將會同步服務端對該對象的任何變動。

 

服務端的AIDL如下:

Bean_Data.aidl:

// IBean_Data.aidl
package com.fei.aidldemo.bean;
// Declare any non-default types here with import statements
parcelable Bean_Data;

Aidl_CommunionInterface.aidl:

// Aidl_CommunionInterface.aidl
package com.fei.aidldemo;
import com.fei.aidldemo.bean.Bean_Data;
// Declare any non-default types here with import statements

interface Aidl_CommunionInterface {
    void sendMsg(in Bean_Data msg);
    String accpetMsg(Aidl_CommunionInterface callBack);
}

之後進行Sync  AS將會在如下目錄產生一個java文件,此文件將會在客戶端使用,目錄如下:

之後,在服務端需要編寫一個Service,找服務中進行數據的交換傳遞的邏輯,如下:

public class Service_Aidl extends Service {

    private Aidl_CommunionInterface callBack;
    private int num = 0;

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

    private Aidl_CommunionInterface.Stub mAidl_communionInterface = new Aidl_CommunionInterface.Stub() {

        @Override
        public void sendMsg(Bean_Data msg) throws RemoteException {

        }

        @Override
        public String accpetMsg(Aidl_CommunionInterface mCallBack) throws RemoteException {
            callBack = mCallBack;
            if(null == callBack){
                return "失敗";
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true){
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Bean_Data data = new Bean_Data();
                        data.setData(num+"");
                        try {
                            callBack.sendMsg(data);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        num ++;
                    }
                }
            }).start();
            return "這是AIDL傳遞過來的數據";
        }
    };

}

此處爲了偷懶,數據傳遞,以及服務端主動發送數據的回調使用同一個AIDL實現,僅僅使用不同方法進行區分,sendMsg方法爲每經過1S主動向客戶端上報數據,數據爲已經序列化的對象,accpetMsg方法爲客戶端主動查詢的接口

下面爲客戶端的內容:

首先應該先將上面服務端生成的.java文件複製到客戶端的工程中,主要路徑應該與其在服務端的路徑一致

客戶端路徑如下:

 

MainActivity.java代碼如下:

public class MainActivity extends AppCompatActivity {

    private TextView main_get_tv;
    private Button main_get_bt;

    private Aidl_CommunionInterface mAidl_communionInterface;

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

        initBindService();

        initView();


    }


    private void initBindService(){
        Intent intent = new Intent();
        intent.setAction("com.fei.aidl");
        intent.setPackage("com.fei.aidldemo");
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }


    private void  initView(){
        main_get_tv = findViewById(R.id.main_get_tv);
        main_get_bt = findViewById(R.id.main_get_bt);

        main_get_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    main_get_tv.setText( mAidl_communionInterface.accpetMsg(new Aidl_CommunionInterface.Stub() {

                        @Override
                        public void sendMsg(final Bean_Data msg) throws RemoteException {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    main_get_tv.setText(msg.getData());
                                }
                            });
                        }

                        @Override
                        public String accpetMsg(Aidl_CommunionInterface callBack) throws RemoteException {
                            return null;
                        }
                    }));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }



    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mAidl_communionInterface = Aidl_CommunionInterface.Stub.asInterface(iBinder);
            main_get_tv.setText("連接成功");
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

    @Override
    protected void onStop() {
        super.onStop();
        if(null != mServiceConnection){
            unbindService(mServiceConnection);
        }
    }
}

需注意的是在BingService時,action和package的值應該與服務端的Service在清單文件中的值一致

服務端的Service在清單文件:

運行,安裝,之後先打開服務端,按Home鍵退出,在打開客戶端,點擊獲取數據按鈕,可以正常獲取數據

上述代碼中包含基礎類型數據的傳遞,服務端的主動下發數據,以及非基礎類型數據(序列化的對象)的傳遞

服務端和客戶端的下載地址:https://download.csdn.net/download/u011685953/11103408

AIDLDemo爲服務端      AIDLDemoGet爲客戶端

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