Android提供的一种快速实现binder进程通信的工具,也可以不用AIDL,自己实现binder来达到同样的效果,但是会比较复杂,后面我会写文章来细说,先给出demo地址。
AIDL支持的数据类型 : String,int,long,boolean,float,double,ArrayList,HashMap,Parcelable等
因为可以让我们更轻松的使用binder,专注写client、service,而不必关心ServiceManager、Binder驱动,那么问题又来了,为什么要用binder来进程通信呢?后续有文章单独来说,那问题又又来了,Android为什么需要进程通信呢?进程通信的方式有哪些呢?一个个问题是不是纷至沓来,感觉压的自己透不过气,一定要知道个所以然呢?客官莫急,且听我细细道来。但是当前第一步就是要学会用AIDL实现跨进程的通信!
新建AIDL文件,会在src/main下面自动新建一个叫aidl的文件夹
// Declare any non-default types here with import statements
/**除了默认的基本类型,就是下面直接生成出来的方法自带的这6种类型不需要import之外,其他的都需要手动import
- 其他类型包括下面几种:
*List 接口(会自动将List接口转为 ArrayList),且集合的每个元素都必须要么是基本类型,要么是Parcelable实现类
*Map 接口(会自动将 Map 接口转为 HashMap),且每个元素的 key 和 value 要么是基本类型,要么是Parcelable实现类
*Parcelable 的实现类
*AIDL 接口本身
*/
import com.ly.aidltest.Student;
interface IMyAidlInterface {
/**
* 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);
//定义两个方法,也就是提供给客户端的服务
List<Student> getStudent();
//这里的in 是有讲究的
void addStudent(in Student stu);
}
所有非基本类型的参数都需要标签来表明这个数据的去向:
定义上面AIDL文件用到的java对象
public class Student implements Parcelable {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
protected Student(Parcel in) {
name = in.readString();
age = in.readInt();
}
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];
}
};
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;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
}
除了定义Java对象之外,还需要一步,复制第一步新建的xxx.aidl文件,重命名为java对象同样的名字:
新建service服务端
public class MyService extends Service {
private List<Student> list = new ArrayList<>();
private static final String TAG = "MyService";
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: ");
list.add(new Student("小明", 12));
list.add(new Student("小红", 13));
list.add(new Student("小军", 14));
}
private IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public List<Student> getStudent() throws RemoteException {
return list;
}
@Override
public void addStudent(Student stu) throws RemoteException {
Log.e(TAG, "setStudent: " );
list.add(stu);
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind: " );
return mBinder;
}
}
并在manifest里面声明
<service android:name=".MyService"/>
客户端启动服务端
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private IMyAidlInterface sub;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
sub = IMyAidlInterface.Stub.asInterface(service);
try {
List<Student> list = sub.getStudent();
for(Student s : list){
Log.e(TAG, "onServiceConnected: "+s.getName()+" age:"+s.getAge());
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService(new Intent(this,MyService.class),connection,BIND_AUTO_CREATE);
}
}
达到的初步结果就是
客户端可以跨进程拿到服务端的数据
可以测试一下
//manifest中:
<service
android:name=".MyService"
android:process=":another">
<intent-filter>
<action android:name="com.ly.aidltest.MyService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
//activity中:
Intent intent = new Intent();
//5.0之后如果使用隐式启动service需要加上package,防止冲突,当然如果启动的是别的APP的service,要用目标的名字
intent.setPackage(getPackageName());
intent.setAction("com.ly.aidltest.MyService");
bindService(intent,connection,BIND_AUTO_CREATE);