使用AIDL(二)传递数据
AIDL默认支持的数据类型
IData.aidl
package jun.server;
// Declare any non-default types here with import statements
interface IBaseData {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
// 不支持short类型
void basicTypes(byte aByte, int anInt, long aLong,
boolean aBoolean,
float aFloat, double aDouble,
char aChar,
String aString, CharSequence aCharSequence,
inout List<String> aList);
}
除short外的Java八大基本数据类型,String、CharSequence、包含前面支持的数据类型的List。
传递自定义数据类型
1、服务端
1)创建自定义数据类型Person类必须继承Parcelable,这样对象才能使用于传输或存储。
app/src/main/java/jun.server.model/Person.java
public class Person implements Parcelable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(Parcel source) {
this.name = source.readString();
this.age = source.readInt();
}
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);
}
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 String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2)创建Person类对应的AIDL文件
app/src/main/aidl/jun.server.model/Person.aidl
// Person.aidl
package jun.server.model;
// Declare any non-default types here with import statements
parcelable Person;
3)创建AIDL接口文件
ICustomData.aidl
// ICustomData.aidl
package jun.server;
// Declare any non-default types here with import statements
// 注意:Person.aidl和Person.java的位置要一致
// 需要导入自定义数据的类型
import jun.server.model.Person;
interface ICustomData {
List<Person> add(in Person person);
}
其中add(in Person person)里面有个in这是什么意思?
首先Person在发送方发送之前作为输出需要进行打包才能够传输,然后在接收方收到后作为输入需要进行拆包还原。而无论是打包还是拆包都非常消耗资源,所以如果只是作为输入那就是in,只是作为输出就是out,同时作为输入输出就是inout。这里由于Person是从客户端传过来的,所以是作为输入也就是in。
4)创建服务
RemoteService.java
/**
* 远程Service
*/
public class RemoteService extends Service {
private ArrayList<Person> persons;
// 解释:Stub是继承Binder的
ICustomData.Stub mBinder = new ICustomData.Stub() {
@Override
public List<Person> add(Person person) throws RemoteException {
persons.add(person);
return persons;
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
persons = new ArrayList<>();
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
// 服务销毁前将Binder置空,方便垃圾回收器回收资源。
mBinder = null;
}
}
5)记得注册Service
<service android:name=".RemoteService">
<intent-filter>
<action android:name="jun.server.RemoteService"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
2、客户端
1)直接将服务端的Person.aidl、ICustomData.aidl和Person.java拷贝到客户端
app/src/main/aidl/jun.server.model/Person.aidl
app/src/main/aidl/jun.server/ICustomData.aidl
app/src/main/java/jun.server.model/Person.java
注意:包名一样。
2)创建Activity的布局
activity_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/bind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="绑定服务"/>
<Button
android:id="@+id/unbind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="解除绑定"/>
<Button
android:id="@+id/invoke_method"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="调用远程服务的方法"/>
</LinearLayout>
3)在Activity中绑定远程服务并调用它的方法
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ICustomData mICustomData;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 拿到远程服务的代理
mICustomData = ICustomData.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mICustomData = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.bind_service).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 设置Intent目标是jun.server包的RemoteService
Intent intent = new Intent("jun.server.RemoteService");
intent.setPackage("jun.server");
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
Toast.makeText(MainActivity.this, "已绑定服务", Toast.LENGTH_SHORT).show();
}
});
findViewById(R.id.unbind_service).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (serviceConnection != null) {
unbindService(serviceConnection);
// 解除绑定时需要回收mIStudent连接资源
mICustomData = null;
Toast.makeText(MainActivity.this, "已解除绑定", Toast.LENGTH_SHORT).show();
}
}
});
findViewById(R.id.invoke_method).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mICustomData != null) {
try {
List<Person> persons = mICustomData.add(new Person("Tom", 18));
Log.i(TAG, persons.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, "请先绑定服务", Toast.LENGTH_SHORT).show();
}
}
});
}
}
3、运行
先运行服务端再运行客户端,点击“绑定服务”按钮让客户端绑定服务端的服务,再点击“调用远程服务的方法”按钮调用服务端的getName()方法,最后点击“解除绑定”按钮解除绑定。运行结果如下:
I/MainActivity: [Person{name='Tom', age=18}]
参考
墨客网:AIDL-小白成长记(视频教程)