在android开发过程中,为了让其他的应用程序,也可以访问本应用程序的服务,android系统采用远程过程调用来实现。android通过接口来公开定义的服务。我们将能够夸进程访问的服务成为AIDL服务(Android Interface Definition Language)。本节主要讲述通过aidl服务来传递数据。aidl支持的数据类型“简单数据类型、String和char、List和Map、aidl自动生成的接口、实现android.Parcelable的类。
1.建立aidl服务
在Eclipse中建立android_adil应用程序,在java的包目录中建立一个IMyService.aidl文件.
1 package com.example.android_demo_aidl;
2 import com.example.android_demo_aidl.Person;
3 interface IMyService
4 {
5 Map getMap(in String key,in Person person);
6 Person getPerson();
7 }
Person是实现了parcelable接口的类,需要使用import导入。in表示该值可以在客户端设置,out表示该值可以在服务端设置,inout表示该值既可以在客户端设置,也可以再服务端设置。如果aidl正确,会自动生成IMyService.java文件。
在包中建立Person类。
1 package com.example.android_demo_aidl;
2
3 import android.os.Parcel;
4 import android.os.Parcelable;
5
6 public class Person implements Parcelable {
7
8 private int id;
9 private String name;
10 private int age;
11 public static final Parcelable.Creator<Person> CREATOR= new Parcelable.Creator<Person>() {
12
13 @Override
14 public Person[] newArray(int size) {
15 // TODO Auto-generated method stub
16 return new Person[size];
17 }
18
19 @Override
20 public Person createFromParcel(Parcel source) {
21 // TODO Auto-generated method stub
22 return new Person(source);
23 }
24 };
25 public Person()
26 {
27 }
28 private Person(Parcel in)
29 {
30 readFormParce(in);
31 }
32 private void readFormParce(Parcel in) {
33 // TODO Auto-generated method stub
34 id=in.readInt();
35 name=in.readString();
36 age=in.readInt();
37
38 }
39 public int describeContents()
40 {
41 return 0;
42 }
43 public void writeToParcel(Parcel dest,int flags)
44 {
45 dest.writeInt(id);
46 dest.writeString(name);
47 dest.writeInt(age);
48 }
49 public int getId()
50 {
51 return id;
52 }
53 public void setId(int id)
54 {
55 this.id=id;
56 }
57 public String getName()
58 {
59 return name;
60 }
61 public void setName(String name)
62 {
63 this.name=name;
64 }
65 public int getAge()
66 {
67 return age;
68 }
69 public void setAge(int age)
70 {
71 this.age=age;
72 }
73 }
Person类定义name,age等成员变量,实现了接口parcelable。同时必须定义CREATOR的常量,类型为Parcelable.Creator。在writeToParcel中将序列化的值传入Parcel。
建立Person.aidl
parcelable Person;
编写MyService类
1 package com.example.android_demo_aidl;
2
3 import java.util.HashMap;
4 import java.util.Map;
5
6 import android.app.Service;
7 import android.content.Intent;
8 import android.os.IBinder;
9 import android.os.RemoteException;
10 import android.util.Log;
11
12 public class MyService extends Service {
13
14 public class MyServiceImpl extends IMyService.Stub
15 {
16
17 @Override
18 public Map getMap(String key, Person person) throws RemoteException {
19 // TODO Auto-generated method stub
20 Map map = new HashMap<String,String>();
21 map.put("id", person.getId());
22 map.put("age", person.getAge());
23 map.put("name", person.getName());
24 map.put("person", person);
25 return map;
26 }
27
28 @Override
29 public Person getPerson() throws RemoteException {
30 // TODO Auto-generated method stub
31 Person person = new Person();
32 person.setAge(18);
33 person.setId(1);
34 person.setName("Tom");
35 return person;
36 }
37
38
39
40 }
41 @Override
42 public IBinder onBind(Intent intent) {
43 // TODO Auto-generated method stub
44 return new MyServiceImpl();
45 }
46 @Override
47 public void onCreate() {
48 // TODO Auto-generated method stub
49 super.onCreate();
50 Log.d("test", "oncreate");
51 }
52 }
在MyService类中定义一个新类MyServiceIm继承于IMyService.Stub.需要实现在接口中定义的方法。MyService类继承android.Service,在绑定方法中,返回一个实例。
最后,在AndroidManifest.xml中配置该服务。
1 <service android:name=".MyService">
2 <intent-filter >
3 <action android:name="com.example.android_demo_aidl.IMyService"/>
4 </intent-filter>
5 </service>
android:name,在客户端通过该id调用服务。
2.调用服务
在Eclipse中建立新的android应用程序,android_ail_client。在调用服务之前,需要绑定服务,通过bindService进行服务的绑定。将服务端自动生成的IMyservice.java连同包一起复制到新的应用程序用。程序结构如下图
1 package com.example.android_demo_aidl_client;
2
3 import com.example.android_demo_aidl.IMyService;
4
5 import android.support.v7.app.ActionBarActivity;
6 import android.content.ComponentName;
7 import android.content.Context;
8 import android.content.Intent;
9 import android.content.ServiceConnection;
10 import android.os.Bundle;
11 import android.os.IBinder;
12 import android.util.Log;
13 import android.view.Menu;
14 import android.view.MenuItem;
15 import android.view.View;
16 import android.view.View.OnClickListener;
17 import android.widget.Button;
18 import android.widget.TextView;
19
20 public class MainActivity extends ActionBarActivity implements OnClickListener {
21
22 private Button btnstart;
23 private Button btninvoke;
24 private IMyService myService=null;
25 private TextView textView;
26 private ServiceConnection conn=new ServiceConnection() {
27
28 @Override
29 public void onServiceDisconnected(ComponentName name) {
30 // TODO Auto-generated method stub
31 Log.d("test", "绑定错误");
32 }
33
34 @Override
35 public void onServiceConnected(ComponentName name, IBinder service) {
36 // TODO Auto-generated method stub
37 myService=IMyService.Stub.asInterface(service);
38 btninvoke.setEnabled(true);
39 }
40 };
41 @Override
42 protected void onCreate(Bundle savedInstanceState) {
43 super.onCreate(savedInstanceState);
44 setContentView(R.layout.activity_main);
45 btnstart=(Button)findViewById(R.id.button1);
46 btninvoke=(Button)findViewById(R.id.button2);
47 textView=(TextView)findViewById(R.id.textView1);
48
49 btninvoke.setOnClickListener(this);
50 btnstart.setOnClickListener(this);
51 }
52
53 @Override
54 public boolean onCreateOptionsMenu(Menu menu) {
55 // Inflate the menu; this adds items to the action bar if it is present.
56 getMenuInflater().inflate(R.menu.main, menu);
57 return true;
58 }
59
60 @Override
61 public boolean onOptionsItemSelected(MenuItem item) {
62 // Handle action bar item clicks here. The action bar will
63 // automatically handle clicks on the Home/Up button, so long
64 // as you specify a parent activity in AndroidManifest.xml.
65 int id = item.getItemId();
66 if (id == R.id.action_settings) {
67 return true;
68 }
69 return super.onOptionsItemSelected(item);
70 }
71
72 @Override
73 public void onClick(View v) {
74 // TODO Auto-generated method stub
75 switch(v.getId())
76 {
77 case R.id.button1:
78 bindService(new Intent("com.example.android_demo_aidl.IMyService"), conn, Context.BIND_AUTO_CREATE);
79 break;
80 case R.id.button2:
81 try
82 {
83 String s="";
84 s="person.id="+myService.getPerson().getId()+"\n";
85 s+="person.name="+myService.getPerson().getName()+"\n";
86 s+="person.age="+myService.getPerson().getAge();
87 textView.setText(s);
88 }
89 catch(Exception e)
90 {
91 Log.d("test",e.getMessage());
92 }
93 break;
94 }
95 }
96 @Override
97 protected void onDestroy() {
98 // TODO Auto-generated method stub
99 super.onDestroy();
100 unbindService(conn);
101 }
102 }
在该段代码中,通过ServiceConnection获取Aidl服务的对象实例。在调用服务之前需先绑定服务。
3.程序运行截图
运行的时候,需要先运行服务端程序,再运行客户端程序。