传递复杂数据的AIDL服务
AIDL是一种接口定义语言,用于约束两个进程间的通信规则,供编译器生成代码,实现
Android 设备上的进程间通信。
进程之间的通信信息首先会被转换成AIDL 协议消息,然后发送给对方,对方受到AIDL协
议消息后再转换成相应的对象。
AIDL服务工程目录:src\ch08\ch08_complextypeaidl
客户端程序工程目录:src\ch08\ch08_complextypeaidlclient
AIDL服务只支持有限的数据类型,因此,如果用AIDL服务传递一些复杂的数据就需要做更一步处理。AIDL服务支持的数据类型如下:
Java的简单类型(int、char、boolean等)。不需要导入(import)。
String和CharSequence。不需要导入(import)。
List和Map。但要注意,List和Map对象的元素类型必须是AIDL服务支持的数据类型。不需要导入(import)。
AIDL自动生成的接口。需要导入(import)。
实现android.os.Parcelable接口的类。需要导入(import)。
其中后两种数据类型需要使用import进行导入,将在本章的后面详细介绍。
传递不需要import的数据类型的值的方式相同。传递一个需要import的数据类型的值(例如,实现android.os.Parcelable接口的类)的步骤略显复杂。除了要建立一个实现android.os.Parcelable接口的类外,还需要为这个类单独建立一个aidl文件,并使用parcelable关键字进行定义。具体的实现步骤如下:
(1)建立一个IMyService.aidl文件,并输入如下代码:
1. package net.blogjava.mobile.complex.type.aidl;
2. import net.blogjava.mobile.complex.type.aidl.Product;
3. interface IMyService
4. {
5. Map getMap(in String country, in Product product);
6. Product getProduct();
7. }
在编写上面代码时要注意如下两点:
Product是一个实现android.os.Parcelable接口的类,需要使用import导入这个类。
如果方法的类型是非简单类型,例如,String、List或自定义的类,需要使用in、out或inout修饰。其中in表示这个值被客户端设置;out表示这个值被服务端设置;inout表示这个值既被客户端设置,又被服务端设置。
(2)编写Product类。该类是用于传递的数据类型,代码如下:
1. package net.blogjava.mobile.complex.type.aidl;
2.
3. import android.os.Parcel;
4. import android.os.Parcelable;
5.
6. public class Product implements Parcelable
7. {
8. private int id;
9. private String name;
10. private float price;
11. public static final Parcelable.Creator<Product>
CREATOR = new Parcelable.Creator<Product>()
12. {
13. public Product createFromParcel(Parcel in)
14. {
15. return new Product(in);
16. }
17.
18. public Product[] newArray(int size)
19. {
20. return new Product[size];
21. }
22. };
23. public Product()
24. {
25. }
26. private Product(Parcel in)
27. {
28. readFromParcel(in);
29. }
30. @Override
31. public int describeContents()
32. {
33. return 0;
34. }
35. public void readFromParcel(Parcel in)
36. {
37. id = in.readInt();
38. name = in.readString();
39. price = in.readFloat();
40. }
41. @Override
42. public void writeToParcel(Parcel dest, int flags)
43. {
44. dest.writeInt(id);
45. dest.writeString(name);
46. dest.writeFloat(price);
47. }
48. // 此处省略了属性的getter和setter方法
49. ... ...
50. }
在编写Product类时应注意如下3点:
Product类必须实现android.os.Parcelable接口。该接口用于序列化对象。在Android中之所以使用Pacelable接口序列化,而不是java.io.Serializable接口,是因为Google在开发Android时发现Serializable序列化的效率并不高,因此,特意提供了一个Parcelable接口来序列化对象。
在Product类中必须有一个静态常量,常量名必须是CREATOR,而且CREATOR常量的数据类型必须是Parcelable.Creator。
在writeToParcel方法中需要将要序列化的值写入Parcel对象。
(3)建立一个Product.aidl文件,并输入如下内容:
1. parcelable Product;
8.4.2 建立AIDL服务的步骤(3)
8.4.2 建立AIDL服务的步骤(3)
(4)编写一个MyService类,代码如下:
1. package net.blogjava.mobile.complex.type.aidl;
2.
3. import java.util.HashMap;
4. import java.util.Map;
5. import android.app.Service;
6. import android.content.Intent;
7. import android.os.IBinder;
8. import android.os.RemoteException;
9. // AIDL服务类
10. public class MyService extends Service
11. {
12. public class MyServiceImpl extends IMyService.Stub
13. {
14. @Override
15. public Product getProduct() throws RemoteException
16. {
17. Product product = new Product();
18. product.setId(1234);
19. product.setName("汽车");
20. product.setPrice(31000);
21. return product;
22. }
23. @Override
24. public Map getMap(String country, Product
product) throws RemoteException
25. {
26. Map map = new HashMap<String, String>();
27. map.put("country", country);
28. map.put("id", product.getId());
29. map.put("name", product.getName());
30. map.put("price", product.getPrice());
31. map.put("product", product);
32. return map;
33. }
34. }
35. @Override
36. public IBinder onBind(Intent intent)
37. {
38. return new MyServiceImpl();
39. }
40. }
(5)在AndroidManifest.xml文件中配置MyService类,代码如下:
1. <service android:name=".MyService" >
2. <intent-filter>
3. <action android:name="net.blogjava.
mobile.complex.type.aidl.IMyService" />
4. </intent-filter>
5. </service>
在客户端调用AIDL服务的方法与实例52介绍的方法相同,首先将IMyService.java和Product.java文件复制到客户端工程(ch08_complextypeaidlclient),然后绑定AIDL服务,并获得AIDL服务对象,最后调用AIDL服务中的方法。完整的客户端代码如下:
1. package net.blogjava.mobile;
2.
3. import net.blogjava.mobile.complex.type.aidl.IMyService;
4. import android.app.Activity;
5. import android.content.ComponentName;
6. import android.content.Context;
7. import android.content.Intent;
8. import android.content.ServiceConnection;
9. import android.os.Bundle;
10. import android.os.IBinder;
11. import android.view.View;
12. import android.view.View.OnClickListener;
13. import android.widget.Button;
14. import android.widget.TextView;
15.
16. public class Main extends Activity implements OnClickListener
17. {
18. private IMyService myService = null;
19. private Button btnInvokeAIDLService;
20. private Button btnBindAIDLService;
21. private TextView textView;
22. private ServiceConnection serviceConnection = new ServiceConnection()
23. {
24. @Override
25. public void onServiceConnected(ComponentName name, IBinder service)
26. {
27. // 获得AIDL服务对象
28. myService = IMyService.Stub.asInterface(service);
29. btnInvokeAIDLService.setEnabled(true);
30. }
31. @Override
32. public void onServiceDisconnected(ComponentName name)
33. {
34. }
35. };
36. @Override
37. public void onClick(View view)
38. {
39. switch (view.getId())
40. {
41. case R.id.btnBindAIDLService:
42. // 绑定AIDL服务
43. bindService(new Intent("net.blogjava.
mobile.complex.type.aidl.IMyService"),
44. serviceConnection, Context.BIND_AUTO_CREATE);
45. break;
46. case R.id.btnInvokeAIDLService:
47. try
48. {
49. String s = "";
50. // 调用AIDL服务中的方法
51. s = "Product.id = " + myService.
getProduct().getId() + "\n";
52. s += "Product.name = " + myService.
getProduct().getName() + "\n";
53. s += "Product.price = " + myService.
getProduct().getPrice() + "\n";
54. s += myService.getMap("China",
myService.getProduct()).toString();
55. textView.setText(s);
56. }
57. catch (Exception e)
58. {
59. }
60. break;
61. }
62. }
63. @Override
64. public void onCreate(Bundle savedInstanceState)
65. {
66. super.onCreate(savedInstanceState);
67. setContentView(R.layout.main);
68. btnInvokeAIDLService = (Button) findViewById(R.id.btnInvokeAIDLService);
69. btnBindAIDLService = (Button) findViewById(R.id.btnBindAIDLService);
70. btnInvokeAIDLService.setEnabled(false);
71. textView = (TextView) findViewById(R.id.textview);
72. btnInvokeAIDLService.setOnClickListener(this);
73. btnBindAIDLService.setOnClickListener(this);
74. }
75. }
AIDL是一种接口定义语言,用于约束两个进程间的通信规则,供编译器生成代码,实现
Android 设备上的进程间通信。
进程之间的通信信息首先会被转换成AIDL 协议消息,然后发送给对方,对方受到AIDL协
议消息后再转换成相应的对象。
AIDL服务工程目录:src\ch08\ch08_complextypeaidl
客户端程序工程目录:src\ch08\ch08_complextypeaidlclient
AIDL服务只支持有限的数据类型,因此,如果用AIDL服务传递一些复杂的数据就需要做更一步处理。AIDL服务支持的数据类型如下:
Java的简单类型(int、char、boolean等)。不需要导入(import)。
String和CharSequence。不需要导入(import)。
List和Map。但要注意,List和Map对象的元素类型必须是AIDL服务支持的数据类型。不需要导入(import)。
AIDL自动生成的接口。需要导入(import)。
实现android.os.Parcelable接口的类。需要导入(import)。
其中后两种数据类型需要使用import进行导入,将在本章的后面详细介绍。
传递不需要import的数据类型的值的方式相同。传递一个需要import的数据类型的值(例如,实现android.os.Parcelable接口的类)的步骤略显复杂。除了要建立一个实现android.os.Parcelable接口的类外,还需要为这个类单独建立一个aidl文件,并使用parcelable关键字进行定义。具体的实现步骤如下:
(1)建立一个IMyService.aidl文件,并输入如下代码:
1. package net.blogjava.mobile.complex.type.aidl;
2. import net.blogjava.mobile.complex.type.aidl.Product;
3. interface IMyService
4. {
5. Map getMap(in String country, in Product product);
6. Product getProduct();
7. }
在编写上面代码时要注意如下两点:
Product是一个实现android.os.Parcelable接口的类,需要使用import导入这个类。
如果方法的类型是非简单类型,例如,String、List或自定义的类,需要使用in、out或inout修饰。其中in表示这个值被客户端设置;out表示这个值被服务端设置;inout表示这个值既被客户端设置,又被服务端设置。
(2)编写Product类。该类是用于传递的数据类型,代码如下:
1. package net.blogjava.mobile.complex.type.aidl;
2.
3. import android.os.Parcel;
4. import android.os.Parcelable;
5.
6. public class Product implements Parcelable
7. {
8. private int id;
9. private String name;
10. private float price;
11. public static final Parcelable.Creator<Product>
CREATOR = new Parcelable.Creator<Product>()
12. {
13. public Product createFromParcel(Parcel in)
14. {
15. return new Product(in);
16. }
17.
18. public Product[] newArray(int size)
19. {
20. return new Product[size];
21. }
22. };
23. public Product()
24. {
25. }
26. private Product(Parcel in)
27. {
28. readFromParcel(in);
29. }
30. @Override
31. public int describeContents()
32. {
33. return 0;
34. }
35. public void readFromParcel(Parcel in)
36. {
37. id = in.readInt();
38. name = in.readString();
39. price = in.readFloat();
40. }
41. @Override
42. public void writeToParcel(Parcel dest, int flags)
43. {
44. dest.writeInt(id);
45. dest.writeString(name);
46. dest.writeFloat(price);
47. }
48. // 此处省略了属性的getter和setter方法
49. ... ...
50. }
在编写Product类时应注意如下3点:
Product类必须实现android.os.Parcelable接口。该接口用于序列化对象。在Android中之所以使用Pacelable接口序列化,而不是java.io.Serializable接口,是因为Google在开发Android时发现Serializable序列化的效率并不高,因此,特意提供了一个Parcelable接口来序列化对象。
在Product类中必须有一个静态常量,常量名必须是CREATOR,而且CREATOR常量的数据类型必须是Parcelable.Creator。
在writeToParcel方法中需要将要序列化的值写入Parcel对象。
(3)建立一个Product.aidl文件,并输入如下内容:
1. parcelable Product;
8.4.2 建立AIDL服务的步骤(3)
8.4.2 建立AIDL服务的步骤(3)
(4)编写一个MyService类,代码如下:
1. package net.blogjava.mobile.complex.type.aidl;
2.
3. import java.util.HashMap;
4. import java.util.Map;
5. import android.app.Service;
6. import android.content.Intent;
7. import android.os.IBinder;
8. import android.os.RemoteException;
9. // AIDL服务类
10. public class MyService extends Service
11. {
12. public class MyServiceImpl extends IMyService.Stub
13. {
14. @Override
15. public Product getProduct() throws RemoteException
16. {
17. Product product = new Product();
18. product.setId(1234);
19. product.setName("汽车");
20. product.setPrice(31000);
21. return product;
22. }
23. @Override
24. public Map getMap(String country, Product
product) throws RemoteException
25. {
26. Map map = new HashMap<String, String>();
27. map.put("country", country);
28. map.put("id", product.getId());
29. map.put("name", product.getName());
30. map.put("price", product.getPrice());
31. map.put("product", product);
32. return map;
33. }
34. }
35. @Override
36. public IBinder onBind(Intent intent)
37. {
38. return new MyServiceImpl();
39. }
40. }
(5)在AndroidManifest.xml文件中配置MyService类,代码如下:
1. <service android:name=".MyService" >
2. <intent-filter>
3. <action android:name="net.blogjava.
mobile.complex.type.aidl.IMyService" />
4. </intent-filter>
5. </service>
在客户端调用AIDL服务的方法与实例52介绍的方法相同,首先将IMyService.java和Product.java文件复制到客户端工程(ch08_complextypeaidlclient),然后绑定AIDL服务,并获得AIDL服务对象,最后调用AIDL服务中的方法。完整的客户端代码如下:
1. package net.blogjava.mobile;
2.
3. import net.blogjava.mobile.complex.type.aidl.IMyService;
4. import android.app.Activity;
5. import android.content.ComponentName;
6. import android.content.Context;
7. import android.content.Intent;
8. import android.content.ServiceConnection;
9. import android.os.Bundle;
10. import android.os.IBinder;
11. import android.view.View;
12. import android.view.View.OnClickListener;
13. import android.widget.Button;
14. import android.widget.TextView;
15.
16. public class Main extends Activity implements OnClickListener
17. {
18. private IMyService myService = null;
19. private Button btnInvokeAIDLService;
20. private Button btnBindAIDLService;
21. private TextView textView;
22. private ServiceConnection serviceConnection = new ServiceConnection()
23. {
24. @Override
25. public void onServiceConnected(ComponentName name, IBinder service)
26. {
27. // 获得AIDL服务对象
28. myService = IMyService.Stub.asInterface(service);
29. btnInvokeAIDLService.setEnabled(true);
30. }
31. @Override
32. public void onServiceDisconnected(ComponentName name)
33. {
34. }
35. };
36. @Override
37. public void onClick(View view)
38. {
39. switch (view.getId())
40. {
41. case R.id.btnBindAIDLService:
42. // 绑定AIDL服务
43. bindService(new Intent("net.blogjava.
mobile.complex.type.aidl.IMyService"),
44. serviceConnection, Context.BIND_AUTO_CREATE);
45. break;
46. case R.id.btnInvokeAIDLService:
47. try
48. {
49. String s = "";
50. // 调用AIDL服务中的方法
51. s = "Product.id = " + myService.
getProduct().getId() + "\n";
52. s += "Product.name = " + myService.
getProduct().getName() + "\n";
53. s += "Product.price = " + myService.
getProduct().getPrice() + "\n";
54. s += myService.getMap("China",
myService.getProduct()).toString();
55. textView.setText(s);
56. }
57. catch (Exception e)
58. {
59. }
60. break;
61. }
62. }
63. @Override
64. public void onCreate(Bundle savedInstanceState)
65. {
66. super.onCreate(savedInstanceState);
67. setContentView(R.layout.main);
68. btnInvokeAIDLService = (Button) findViewById(R.id.btnInvokeAIDLService);
69. btnBindAIDLService = (Button) findViewById(R.id.btnBindAIDLService);
70. btnInvokeAIDLService.setEnabled(false);
71. textView = (TextView) findViewById(R.id.textview);
72. btnInvokeAIDLService.setOnClickListener(this);
73. btnBindAIDLService.setOnClickListener(this);
74. }
75. }