之前在Eclipse中进行过AIDL的实践,昨天又尝试着在AndroidStudio中实践,看了一些博客,感觉很多步骤还是没说清楚,耽误了一些时间。下面就整理一下关于AIDL实践的详细过程。
1.创建工程
工程名字叫AIDL_practice,有两个可以运行的module,client和server。顾名思义,client就是AIDL实践中的客户端,server是服务端。
2.初始化server
在server的src/main目录下创建AIDL文件,IMyAidl.aidl:
并且在其中添加一个add方法:
然后build一下server这个module,发现IDE为我们生成了一个名叫IMyAidl的Java文件:
这个时候我们就可以新建Service了:
最后别忘记在AndroidManifest.xml文件中声明Service的权限:
<service
android:name=".RemoteService"
android:enabled="true"
android:exported="true"/>
3.初始化client
然后我们把之前自己写的AIDL文件,IMyAidl.aidl,copy到client的同名目录下
再build一下client这个module,IDE同样为我们生成了一个名叫IMyAidl的Java文件,然后我们就开始写客户端逻辑了:
public class ClientActivity extends AppCompatActivity {
private IMyAidl iMyAidl;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iMyAidl = IMyAidl.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
iMyAidl = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
initView();
bindService();
}
private void initView() {
final EditText num1Edt = (EditText) findViewById(R.id.num1);
final EditText num2Edt = (EditText) findViewById(R.id.num2);
Button addBtn = (Button) findViewById(R.id.add);
final TextView resultTv = (TextView) findViewById(R.id.result);
addBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String num1 = num1Edt.getText().toString().trim();
String num2 = num2Edt.getText().toString().trim();
if (TextUtils.isEmpty(num1)) {
Toast.makeText(ClientActivity.this, "请输入第一个数字", Toast.LENGTH_LONG).show();
} else if (TextUtils.isEmpty(num2)) {
Toast.makeText(ClientActivity.this, "请输入第二个数字", Toast.LENGTH_LONG).show();
} else {
if (iMyAidl != null) {
try {
int result = iMyAidl.add(Integer.valueOf(num1), Integer.valueOf(num2));
resultTv.setText(result + "");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
});
}
private void bindService() {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.aidl.tsnt.server", "com.aidl.tsnt.server.RemoteService"));
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
}
对应的layout,activity_client.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_client"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".ClientActivity">
<EditText
android:id="@+id/num1"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:gravity="center"
android:hint="num1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+" />
<EditText
android:id="@+id/num2"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:gravity="center"
android:hint="num2" />
<Button
android:id="@+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="=" />
<TextView
android:id="@+id/result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:textColor="@android:color/holo_red_dark" />
</LinearLayout>
然后我们把server和client都运行起来,client调用远程server端的RemoteService就可以进行加法运算了:
4.传递自定义数据类型
AIDL支持Java的基本数据类型,还有String,CharSequence,List,Map和实现了Parcelable的自定义数据类型。当然这里所指的List和Map中的元素也必须是支持AIDL的数据类型。
下面就介绍一下在AIDL中如何传递自定义数据类型。
在sever中新建一个Dog类:
public class Dog implements Parcelable {
int age;
public Dog(int age) {
this.age = age;
}
protected Dog(Parcel in) {
age = in.readInt();
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static final Creator<Dog> CREATOR = new Creator<Dog>() {
@Override
public Dog createFromParcel(Parcel in) {
return new Dog(in);
}
@Override
public Dog[] newArray(int size) {
return new Dog[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
}
}
再新建一个aidl配置文件,文件名必须使用Dog,否则系统编译无法找到或者识别Dog。但是得注意到这里如果直接创建的话,会遇到一个错误提示:
Interface Name must be unique
需要我们先新建一个其他名字的xx.aidl,再将xx.aidl重命名为Dog.aidl,内容如下:
// Dog.aidl
package com.aidl.tsnt.server;
parcelable Dog;
然后修改IMyAidl.aidl:
// IMyAidl.aidl
package com.aidl.tsnt.server;
import com.aidl.tsnt.server.Dog;//导包不要忘记
interface IMyAidl {
int add(int num1,int num2);
List<Dog> addDog(in Dog dog);//这里的in注意不要少
}
然后重新build,修改RemoteService的内容:
public class RemoteService extends Service {
private List<Dog> mDogs = new ArrayList<>();
Binder mBinder = new IMyAidl.Stub() {
@Override
public int add(int num1, int num2) throws RemoteException {
return num1 + num2;
}
@Override
public List<Dog> addDog(Dog dog) throws RemoteException {
mDogs.add(dog);
return mDogs;
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
到这里server端已经修改完毕了,我们再看一下server的目录结构:
接下来是client端
1.将server目录下src/main下的aidl整个包复制粘贴到client下对应的位置,覆盖原来的文件
2.将server目录下src/main下的Dog文件以及它所在文件夹复制到client下对应的位置
然后重新build,修改client端中的逻辑:
public class ClientActivity extends AppCompatActivity {
private IMyAidl iMyAidl;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iMyAidl = IMyAidl.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
iMyAidl = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
initView();
bindService();
}
private void initView() {
final EditText num1Edt = (EditText) findViewById(R.id.num1);
final EditText num2Edt = (EditText) findViewById(R.id.num2);
Button addBtn = (Button) findViewById(R.id.add);
final TextView resultTv = (TextView) findViewById(R.id.result);
final TextView printTv = (TextView) findViewById(R.id.print);
addBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String num1 = num1Edt.getText().toString().trim();
String num2 = num2Edt.getText().toString().trim();
if (TextUtils.isEmpty(num1)) {
Toast.makeText(ClientActivity.this, "请输入第一个数字", Toast.LENGTH_LONG).show();
} else if (TextUtils.isEmpty(num2)) {
Toast.makeText(ClientActivity.this, "请输入第二个数字", Toast.LENGTH_LONG).show();
} else {
if (iMyAidl != null) {
try {
int result = iMyAidl.add(Integer.valueOf(num1), Integer.valueOf(num2));
// resultTv.setText(result + "");
List<Dog> dogs = iMyAidl.addDog(new Dog(result));
StringBuffer buffer = new StringBuffer();
buffer.append("现在有");
for (int i = 0; i < dogs.size(); i++) {
buffer.append(dogs.get(i).getAge() + "岁,");
}
buffer.append("共" + dogs.size() + "只狗");
printTv.setText(buffer);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
});
}
private void bindService() {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.aidl.tsnt.server", "com.aidl.tsnt.server.RemoteService"));
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
}
还有对应的layout,activity_client.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_client"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".ClientActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/num1"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:gravity="center"
android:hint="num1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+" />
<EditText
android:id="@+id/num2"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:gravity="center"
android:hint="num2" />
<Button
android:id="@+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="=" />
<TextView
android:id="@+id/result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:textColor="@android:color/holo_red_dark" />
</LinearLayout>
<TextView
android:id="@+id/print"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="10dp" />
</LinearLayout>
最后运行client和server,如下图:
至此,AIDL实践完毕。
源码地址:https://github.com/tingshuonitiao/AIDL_practice