大家都知道在Android中通过AIDL可以跨进程调用Service中的数据,网上也有很多实例,但是大部分实例都是关于基本数据类型的远程调用,很少讲到复杂数据的调用,今天我用一个例子来演示一下怎样用AIDL Service 传递复杂数据。
我们分2步开始:
第一步:部署我们的服务端,也就是Service端:
1:在Service端我先自定义2个类 型:Person和Pet。因为我们需要跨进程传递Person对象和Pet对象,所以Person类和Pet类都必须实现Parcelable接口,并 要求在实现类中定义一个名为CREATER,类型为Parcelable.creator的静态Field。
代码如下:
1 package com.example.remoteservice;
2
3 import android.os.Parcel;
4 import android.os.Parcelable;
5
6 public class Person implements Parcelable {
7 int id;
8 String name;
9 String pass;
10
11 public Person() {
12
13 }
14
15 public Person(int id, String name, String pass) {
16 this.id = id;
17 this.name = name;
18 this.pass = pass;
19 }
20
21 @Override
22 public boolean equals(Object o) {
23 if (this == o) {
24 return true;
25 }
26 if (o == null) {
27 return false;
28 }
29
30 if (getClass() != o.getClass()) {
31 return false;
32 }
33 Person other = (Person) o;
34
35 if (name == null) {
36 if (other.name != null) {
37 return false;
38 }
39 } else if (!name.equals(other.name)) {
40 return false;
41 }
42
43 if (pass == null) {
44 if (other.pass != null) {
45 return false;
46 }
47 } else if (!pass.equals(other.pass)) {
48 return false;
49 }
50
51 return true;
52 }
53
54 @Override
55 public int hashCode() {
56 final int prime = 31;
57 int result = 1;
58 result = prime * result + (name == null ? 0 : name.hashCode());
59 result = prime * result + (pass == null ? 0 : pass.hashCode());
60 return result;
61 }
62
63 @Override
64 public int describeContents() {
65
66 return 0;
67 }
68
69 @Override
70 public void writeToParcel(Parcel arg0, int arg1) {
71 arg0.writeInt(id);
72 arg0.writeString(name);
73 arg0.writeString(pass);
74 }
75
76 public static final Parcelable.Creator<Person> CREATOR = new Creator<Person>() {
77
78 @Override
79 public Person createFromParcel(Parcel source) {
80
81 return new Person(source.readInt(), source.readString(), source.readString());
82 }
83
84 @Override
85 public Person[] newArray(int size) {
86
87 return new Person[size];
88 }
89 };
90
91 public int getId() {
92 return id;
93 }
94
95 public void setId(int id) {
96 this.id = id;
97 }
98
99 public String getName() {
100 return name;
101 }
102
103 public void setName(String name) {
104 this.name = name;
105 }
106
107 public String getPass() {
108 return pass;
109 }
110
111 public void setPass(String pass) {
112 this.pass = pass;
113 }
114
115 }
因为我们会对Person进行比较,所以在Person类中我重写了
public int hashCode() 和 public boolean equals(Object o)方法
1 package com.example.remoteservice;
2
3 import android.os.Parcel;
4 import android.os.Parcelable;
5
6 public class Pet implements Parcelable {
7 String name;
8 float weight;
9
10 public Pet(String name, float weight) {
11 this.name = name;
12 this.weight = weight;
13 }
14
15 public String getName() {
16 return name;
17 }
18
19 public void setName(String name) {
20 this.name = name;
21 }
22
23 public float getWeight() {
24 return weight;
25 }
26
27 public void setWeight(float weight) {
28 this.weight = weight;
29 }
30
31 @Override
32 public int describeContents() {
33
34 return 1;
35 }
36
37 @Override
38 public void writeToParcel(Parcel dest, int flags) {
39 dest.writeString(name);
40 dest.writeFloat(weight);
41
42 }
43
44 public static final Parcelable.Creator<Pet> CREATOR = new Creator<Pet>() {
45
46 @Override
47 public Pet createFromParcel(Parcel source) {
48
49 return new Pet(source.readString(), source.readFloat());
50 }
51
52 @Override
53 public Pet[] newArray(int size) {
54
55 return new Pet[size];
56 }
57 };
58
59 @Override
60 public String toString() {
61
62 return "name:" + this.name + ";weight:" + this.weight;
63 }
64
65 }
2:创建完自定义类型之后还需要用AIDL来定义它们,Person.aidl和Pet.aidl的代码如下:
1 package com.example.remoteservice;
2 parcelable Person;
1 package com.example.remoteservice;
2 parcelable Pet;
3:完成1,2之后就可以使用AIDL定义通信接口了,在这里我定义一个IPet.aidl的接口,代码如下:
1 package com.example.remoteservice; //必须导入包
2 import com.example.remoteservice.Person; //指定自定义类的位置
3 import com.example.remoteservice.Pet;
4
5 interface IPet
6 {
7 List<Pet> getPets(in Person owner);//这里的in表示Person对象是输入的参数
8 }
4:服务端的最后一步就是实现Service了,当然不要忘了注册Service,代码如下:
1 package com.example.remoteservice;
2
3 import com.example.remoteservice.IPet.Stub;
4
5 import java.util.ArrayList;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9
10 import android.app.Service;
11 import android.content.Intent;
12 import android.os.IBinder;
13 import android.os.RemoteException;
14 import android.util.Log;
15
16 public class RemoteService extends Service {
17
18 private PetBinder petBinder;
19
20 private static Map<Person, List<Pet>> pets = new HashMap<Person, List<Pet>>();
21 static {
22 ArrayList<Pet> list1 = new ArrayList<Pet>();
23 list1.add(new Pet("candy", 2.2f));
24 list1.add(new Pet("sandy", 4.2f));
25 pets.put(new Person(1, "sun", "sun"), list1);
26
27 ArrayList<Pet> list2 = new ArrayList<Pet>();
28 list2.add(new Pet("moon", 5.2f));
29 list2.add(new Pet("hony", 6.2f));
30 pets.put(new Person(1, "csx", "csx"), list2);
31
32 }
33
34 public class PetBinder extends Stub {// 继承IPet接口中的Stub类,Stub类继承了Binder类,所有PetBinder也间接的继承了Binder类
35
36 @Override
37 public List<Pet> getPets(Person owner) throws RemoteException {
38
39 return pets.get(owner);
40 }
41
42 }
43
44 @Override
45 public IBinder onBind(Intent intent) {
46
47 Log.i("csx", "onBind");
48 return petBinder;
49 }
50
51 @Override
52 public void onCreate() {
53
54 super.onCreate();
55 Log.i("csx", "onCreate");
56 petBinder = new PetBinder();// 实例化Binder
57
58 }
59
60 @Override
61 public boolean onUnbind(Intent intent) {
62
63 Log.i("csx", "onUnbind");
64 return super.onUnbind(intent);
65 }
66
67 @Override
68 public void onDestroy() {
69
70 super.onDestroy();
71 Log.i("csx", "onDestroy");
72 }
73
74 }
这是我Service端的部署情况(其中MainActivity可以不用去实现,因为我们只提供服务,没有窗口显示):
第二步:部署客户端:
1.在客户端新建一个包,命名需要和服务端放置 aidl文件的包名相同(我这里是com.example.remoteservice),然后把服务端的 Person.java,Pet.java,Person.aidl,Pet.aidl,IPet.aidl复制到这个包下面
2.在activity中绑定远程服务进行数据交换,layout布局和activity代码如下:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:paddingBottom="@dimen/activity_vertical_margin"
6 android:paddingLeft="@dimen/activity_horizontal_margin"
7 android:paddingRight="@dimen/activity_horizontal_margin"
8 android:paddingTop="@dimen/activity_vertical_margin"
9 tools:context="com.example.remoteclient.RemoteClient" >
10
11 <LinearLayout
12 android:layout_width="match_parent"
13 android:layout_height="match_parent"
14 android:orientation="vertical" >
15
16 <LinearLayout
17 android:layout_width="match_parent"
18 android:layout_height="wrap_content"
19 android:orientation="horizontal" >
20
21 <EditText
22 android:id="@+id/editText_person"
23 android:layout_width="wrap_content"
24 android:layout_height="wrap_content"
25 android:layout_gravity="bottom"
26 android:ems="10" >
27 </EditText>
28
29 <Button
30 android:id="@+id/button_ok"
31 android:layout_width="wrap_content"
32 android:layout_height="wrap_content"
33 android:layout_gravity="bottom"
34 android:text="确定" />
35 </LinearLayout>
36
37 <ListView
38 android:id="@+id/listView_pet"
39 android:layout_width="match_parent"
40 android:layout_height="wrap_content" >
41 </ListView>
42 </LinearLayout>
43
44 </RelativeLayout>
1 package com.example.remoteclient;
2
3 import android.app.Service;
4 import android.content.ComponentName;
5 import android.content.Intent;
6 import android.content.ServiceConnection;
7 import android.os.Bundle;
8 import android.os.IBinder;
9 import android.os.RemoteException;
10 import android.support.v7.app.ActionBarActivity;
11 import android.util.Log;
12 import android.view.View;
13 import android.view.View.OnClickListener;
14 import android.widget.ArrayAdapter;
15 import android.widget.Button;
16 import android.widget.EditText;
17 import android.widget.ListView;
18
19 import com.example.remoteservice.IPet;
20 import com.example.remoteservice.Person;
21 import com.example.remoteservice.Pet;
22
23 import java.util.List;
24
25 public class RemoteClient extends ActionBarActivity {
26
27 public static final String REMOTE_SERVICE_ACTION = "com.example.remoteservice.RemoteService.ACTION";
28 EditText editText;
29 Button button;
30 ListView listView;
31
32 IPet petService;// 声明IPet接口
33 List<Pet> pets;
34 ServiceConnection conn = new ServiceConnection() {
35
36 @Override
37 public void onServiceDisconnected(ComponentName name) {
38 Log.i("csx", "onServiceDisconnected");
39 conn = null;
40 }
41
42 @Override
43 public void onServiceConnected(ComponentName name, IBinder service) {
44 Log.i("csx", "onServiceConnected");
45 petService = IPet.Stub.asInterface(service);// 通过远程服务的Binder实现接口
46
47 }
48 };
49
50 @Override
51 protected void onCreate(Bundle savedInstanceState) {
52 super.onCreate(savedInstanceState);
53 setContentView(R.layout.remote_client_layout);
54 editText = (EditText) findViewById(R.id.editText_person);
55 button = (Button) findViewById(R.id.button_ok);
56 listView = (ListView) findViewById(R.id.listView_pet);
57
58 Intent service = new Intent();
59 service.setAction(REMOTE_SERVICE_ACTION);
60
61 bindService(service, conn, Service.BIND_AUTO_CREATE);// 绑定远程服务
62
63 button.setOnClickListener(new OnClickListener() {
64
65 @Override
66 public void onClick(View v) {
67 String personName = editText.getText().toString();
68 if (personName == null || personName.equals("")) {
69
70 return;
71 }
72
73 try {
74 pets = petService.getPets(new Person(1, personName, personName));// 调用远程service的getPets方法
75 updataListView();
76
77 } catch (RemoteException e) {
78
79 e.printStackTrace();
80 } catch (NullPointerException e) {
81 e.printStackTrace();
82 }
83
84 }
85 });
86
87 }
88
89 public void updataListView() {
90 listView.setAdapter(null);
91
92 if (pets == null || pets.isEmpty()) {
93 return;
94
95 }
96 ArrayAdapter<Pet> adapter = new ArrayAdapter<Pet>(RemoteClient.this,
97 android.R.layout.simple_list_item_1, pets);
98 listView.setAdapter(adapter);
99
100 }
101
102 @Override
103 protected void onDestroy() {
104
105 unbindService(conn);// 解除绑定
106 super.onDestroy();
107 }
108
109 }
到此为止所有的工作都完成了,下面我们看一下效果:我在编辑框中输入“csx”,点击确定,就会显示出服务端RemoteService中pets的相应数据。