Android的進程間通信AIDL使用步驟

雖然很多應用都是在一個進程中,但是同樣的也有很多應用是運行在不同進程中的,一個進程Crash了並不會影響其他的進程。因此在不同的進程中就需要相互通信了。這就引出了IPC(Inter-Process Communication)的概念。AIDL(Android Interface Definition Language)就是實現IPC的一種方式。

AIDL支持的類型:

基本類型、String、CharSequence、List、Map、Parcelable、對象

AIDL傳遞基本類型和對象類型流程

1、AIDL傳遞基本類型

  • 新建一個aidl文件

File - New - AIDL - AIDL File

AndroidStudio會生成一個aidl文件夾,在與java包下同包名的目錄中存放之前新建的aidl文件。在文件中編寫方法,例如

interface MyAidl {
    String getName(); // 獲取姓名
    int getAge(); // 獲取年齡
    int getPid(); // 獲取當前進程,對比是否在同一進程中
}

重新編譯,Build - Make Module xxx。

Build成功後會在build/generated/source/aidl/debug/包名下生成一個aidl文件

  • 新建一個Service返回binder對象,並在Android Meniferst文件中註冊,指定一個進程,注意前面的“:”
<service
    android:name=".MyService"
    android:process=":myProcess"/>
  • 在Service中返回binder對象
public class MyService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    MyAidl.Stub binder = new MyAidl.Stub() {
        @Override
        public String getName() throws RemoteException {
            return "張三";
        }

        @Override
        public int getAge() throws RemoteException {
            return 25;
        }

        @Override
        public int getPid() throws RemoteException {
            return Process.myPid();
        }
    };
}
  • 在Activity中綁定服務
private MyAidl mAidl;

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

    Intent intent = new Intent(this, MyService.class);
    bindService(intent, connection, Service.BIND_AUTO_CREATE);
}

private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        try {
            mAidl = MyAidl.Stub.asInterface(iBinder);
            Log.i("TAG", "Name: " + mAidl.getName() + "\n Age: " + mAidl.getAge() +
                        "\n RemotePid: " + mAidl.getPid() + "\n CurrentPid:" + Process.myPid());
        } catch (RemoteException e) {
                e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        mAidl = null;
    }
};

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

打印Log
基本類型LOG

根據日誌可以看出,的確是不在一個進程中,而且int類型和String類型的數據也成功的傳過來了。

2、AIDL傳遞對象類型

步驟大致和基本類型一致,只是在某些細節上不一樣

  • 新建aidl文件同基本類型,區別在於aidl中的方法類型。

    1. 新建一個bean類,實現Parcelable接口。
public class Person implements Parcelable {
    private String name;
    private int age;
    private int pid;

    public Person(String name, int age, int pid) {
        this.name = name;
        this.age = age;
        this.pid = pid;
    }

    protected Person(Parcel in) {
        name = in.readString();
        age = in.readInt();
        pid = in.readInt();
    }

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

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getPid() {
        return pid;
    }

    public void setPid(int pid) {
        this.pid = pid;
    }

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

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(name);
        parcel.writeInt(age);
        parcel.writeInt(pid);
    }
}
  1. 新建一個與上一步同名的aidl文件,如果是新建一個aidl文件as會提示不能同名,則可以直接New - File就行,在aidl文件中加上parcelable+文件名,p是小寫
package com.cc.ui;
parcelable Person;
  1. 在MyAidl.aidl文件中定義新的方法
package com.cc.ui;
import com.cc.ui.Person;
interface MyAidl {
    Person getPersonInfo();
}

注意上面的import,必須將Person.java的路徑給導進來。然後再重新編譯一下。

  • 在Service中返回binder對象
public class MyService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    MyAidl.Stub binder = new MyAidl.Stub() {
        @Override
        public Person getPersonInfo() throws RemoteException {
            return new Person("張三", 25, Process.myPid());
        }
    };
}
  • 在Activity中綁定服務
private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        try {
            mAidl = MyAidl.Stub.asInterface(iBinder);
            Person personInfo = mAidl.getPersonInfo();
            Log.i("TAG", "Name: " + personInfo.getName() + "\n Age: " + personInfo.getAge() +
                        "\n RemotePid: " + personInfo.getPid() + "\n CurrentPid:" + Process.myPid());
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        mAidl = null;
    }
};

其他部分與基本類型一致。

Log:
對象類型LOG

根據日誌看出獲取成功了。


in out inout

這三個數據流通方式的標籤還沒研究過。

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