天天看点

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 ;
        }

        @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

Android的进程间通信AIDL使用步骤

根据日志可以看出,的确是不在一个进程中,而且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 ;
    }

    @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("张三", , 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:

Android的进程间通信AIDL使用步骤

根据日志看出获取成功了。

in out inout

这三个数据流通方式的标签还没研究过。