Android AIDL--進程間通訊

一 AIDL 是什麼

AIDL(Android 接口定義語言) 是 Android 提供的一種進程間通訊 (IPC) 機制。java

咱們能夠利用它定義客戶端與服務使用進程間通訊 (IPC) 進行相互通訊時都承認的編程接口。android

在 Android 上,一個進程一般沒法訪問另外一個進程的內存。 儘管如此,進程須要將其對象分解成操做系統可以識別的原語,並將對象編組成跨越邊界的對象。編程

編寫執行這一編組操做的代碼是一項繁瑣的工做,所以 Android 會使用 AIDL 來處理。app

經過這種機制,咱們只須要寫好 aidl 接口文件,編譯時系統會幫咱們生成 Binder 接口。dom

 

二 AIDL 支持的數據類型

共 4 種:ide

    1. Java 的基本數據類型
    2. List 和 Map 
      • 元素必須是 AIDL 支持的數據類型
      • Server 端具體的類裏則必須是 ArrayList 或者 HashMap
    3. 其餘 AIDL 生成的接口
    4. 實現 Parcelable 的實體

三 AIDL 編寫步驟

AIDL 的編寫主要爲如下三部分:this

    1. 建立 AIDL 
      • 建立要操做的實體類,實現 Parcelable 接口,以便序列化/反序列化
      • 新建 aidl 文件夾,在其中建立接口 aidl 文件以及實體類的映射 aidl 文件
      • Make project ,生成 Binder 的 Java 文件
    2. 服務端 
      • 建立 Service,在其中建立上面生成的 Binder 對象實例,實現接口定義的方法
      • 在 onBind() 中返回
    3. 客戶端 
      • 實現 ServiceConnection 接口,在其中拿到 AIDL 類
      • bindService()
      • 調用 AIDL 類中定義好的操做請求

四 案例

項目結構圖:spa

 

1.建立AIDL

1.1建立要操做的實體類,實現 Parcelable 接口,以便序列化/反序列化

package net.shunzhi.aidldemo1.bean;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by Administrator on 2018/3/9 0009.
 */

public class Person implements Parcelable {
    private String mName;

    public Person (String name){
        this.mName=name;
    }
    protected Person(Parcel source){
        this.mName=source.readString();
    }


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

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

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

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

    @Override
    public String toString() {
        return "Person{" +
                "mName='" + mName + '\'' +
                '}';
    }
}

 

 

1.2新建 aidl 文件夾,在其中建立接口 aidl 文件以及實體類的映射 aidl 文件

 1.鼠標移到項目上面去,點擊右鍵,而後 new->AIDL->AIDL File,按下鼠標左鍵就會彈出一個框提示生成AIDL文件(IMyAIdlInterface)了操作系統

 自動生成如圖:代理

2.編寫接口IMyAdilInterface.aidl

// IMyAidlInterface.aidl
//第二類AIDL文件
//做用是定義方法接口
package net.shunzhi.aidldemo1;

////導入所須要使用的非默認支持數據類型的包
import net.shunzhi.aidldemo1.bean.Person;

interface IMyAidlInterface {

   //傳參時除了Java基本類型以及String,CharSequence以外的類型
   //都須要在前面加上定向tag,具體加什麼量需而定:in(輸入), out(輸出), inout(輸入輸出)
   void addPerson(in Person person);

   //全部的返回值前都不須要加任何東西,無論是什麼數據類型
   List<Person> getAllPersons();
}

在接口 aidl 文件中定義未來要在跨進程進行的操做,上面的接口中定義了兩個操做:

  • addPerson: 添加 Person
  • getPersonList:獲取 Person 列表

須要注意的是:

    • 非基本類型的數據須要導入,好比上面的 Person,須要導入它的全路徑。 
      • 這裏的 Person 我理解的是 Person.aidl,而後經過 Person.aidl 又找到真正的實體 Person 類。
    • 方法參數中,除了基本數據類型,其餘類型的參數都須要標上方向類型 
      • in(輸入), out(輸出), inout(輸入輸出)

 

 

3.建立實體類Person.aidl

//第一類AIDL文件
//這個文件的做用是引入了一個序列化對象 Book 供其餘的AIDL文件使用
//注意:Person.aidl與Person.java的包名應當是同樣的
package net.shunzhi.aidldemo1.bean;


//parcelable 爲小寫
parcelable Person;

 

2.服務端

2.1建立 Service,在其中建立上面生成的 Binder 對象實例,實現接口定義的方法;而後在 onBind() 中返回

 

package net.shunzhi.aidldemo1;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;

import net.shunzhi.aidldemo1.bean.Person;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2018/3/9 0009.
 */

public class MyAidlService extends Service {

    private String TAG="MyAidlService";
    private List<Person> list;

    /**
     * 建立生成的本地 Binder 對象,實現 AIDL 制定的方法
     */
    private IBinder iBinder=new IMyAidlInterface.Stub() {
        @Override
        public void addPerson(Person person) throws RemoteException {
            list.add(person);
        }

        @Override
        public List<Person> getAllPersons() throws RemoteException {
            return list;
        }
    };


    /**
     * 客戶端與服務端綁定時的回調,返回 mIBinder 後客戶端就能夠經過它遠程調用服務端的方法,即實現了通信
     * @param intent
     * @return
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        list=new ArrayList<>();
        return iBinder;
    }
}

 

2.2在 Manifest 文件中聲明

 

<service android:name=".MyAidlService"
            android:enabled="true"
            android:exported="true"
            android:process=":aidl"
            />

 

3.客戶端

3.1實現 ServiceConnection 接口,在其中拿到 AIDL 類

private ServiceConnection connection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//鏈接後拿到 Binder,轉換成 AIDL,在不一樣進程會返回個代理
aidl=IMyAidlInterface.Stub.asInterface(service);
}

@Override
public void onServiceDisconnected(ComponentName name) {
aidl=null;
}
};

在 Activity 中建立一個服務鏈接對象,在其中調用 IMyAidl.Stub.asInterface() 方法將 Binder 轉爲 AIDL 類

3.2接着綁定服務

 

Intent intent=new Intent(MainActivity.this,MyAidlService.class);
bindService(intent,connection,BIND_AUTO_CREATE);

 

3.3拿到 AIDL 類後,就能夠調用 AIDL 類中定義好的操做,進行跨進程請求

 

private void addPerson(){
        Random random=new Random();
        Person p=new Person("fhasdfh"+random.nextInt(10) );
        try {
            aidl.addPerson(p);
            tv.setText(aidl.getAllPersons().toString());
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

總體代碼:

package net.shunzhi.aidldemo1;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import net.shunzhi.aidldemo1.bean.Person;

import java.util.Random;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView tv;
    private Button bt1,bt2;
    private IMyAidlInterface aidl;


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

    private void initView() {
        tv=findViewById(R.id.tv);
        bt1=findViewById(R.id.bt1);
        bt2=findViewById(R.id.bt2);
        bt1.setOnClickListener(this);
        bt2.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.bt1://綁定服務
                Intent intent=new Intent(MainActivity.this,MyAidlService.class);
                bindService(intent,connection,BIND_AUTO_CREATE);
                break;
            case R.id.bt2:
                addPerson();
                break;
        }
    }

    //拿到 AIDL 類後,就能夠調用 AIDL 類中定義好的操做,進行跨進程請求
    private void addPerson(){
        Random random=new Random();
        Person p=new Person("fhasdfh"+random.nextInt(10) );
        try {
            aidl.addPerson(p);
            tv.setText(aidl.getAllPersons().toString());
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }


    private ServiceConnection connection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //鏈接後拿到 Binder,轉換成 AIDL,在不一樣進程會返回個代理
            aidl=IMyAidlInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            aidl=null;
        }
    };
}

 

效果圖:

相關文章
相關標籤/搜索