跨进程调用Service(AIDL Service)

 

Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。

 

在前一篇文章(关于Android中的四大组件(Service的开启与关闭))中介绍了开发人员如何定制自己的服务,但这些

 

服务并不能被其它的应用程序访问,为了使其它的应用程序也可以访问本应用程序提供的服务,Android系统采用了

 

远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其它的基于RPC的解决方案一样,Android使用一种

 

接口定义语言(Interface Definition Language,IDL)来公开服务的接口,因此,可以将这种跨进程访问的服务称为

 

(Android Interface Definition Language)AIDL服务。

 

 

AIDL服务的建立步骤

 

 

 

建立AIDL服务比普通的服务要复杂一些,具体步骤如下。

 

(1)在Eclipse Android工程的Java源文件目录中建立一个扩展名为aidl的文件,该文件的语法类似于Java代

 

码,但会稍不同。

 

(2)如果aidl文件的内容是正确的,ADT会自动生成一个Java接口文件(*.java)。

 

(3)建立一个服务类(Service的子类)。

 

(4)实现由aidl文件生成的Java接口。

 

(5)在AndroidManifest.xml文件中配置AIDL服务,注意的是标签中android:name的属性值就是客户端

 

要引用该服务的ID,也就是Intent类构造方法的参数值。

 

建立AIDL服务

 

以下程序是服务端创建了一个简单的AIDL服务,这个服务有两个get方法,分别获取姓名和年龄,创建此AIDL服务的步骤

 

如下。

 

(1)建立一个aidl文件,如下图中的IPerson.aidl文件。

 

IPerson.aidl文件的内容如下:

 

package com.aidl;interface IPerson{String getName();int getAge();}

 

 

IPerson.aidl文件的内容与Java代码非常相似,但要注意,不能加修饰符,比如:public、private,同时AIDL服

 

 

 

务不支持的数据类型例如:InputStream、OutputStream等内容。

 

(2)如果IPerson.adil文件中内容正确,ADT会自动生成一个IPerson.java文件。

 

(3)编写一个MyService类,该类继承自Service,在MyService类中定义了一个内联类PersonImpl,该类继承自

 

IPerson.Stub,MyService类的代码如下:

 

 

public class MyService extends Service{public class PersonImpl extends IPerson.Stub{@Overridepublic String getName() throws RemoteException {return "bill";}@Overridepublic int getAge() throws RemoteException {return 25;}}@Overridepublic IBinder onBind(Intent intent) {return new PersonImpl();}}


注意:以上的onBind()方法必须返回PersonImpl对象,否则客户端无法获得服务对象。

 

 

(4)在AndroidManifest.xml文件中配置MyService类,代码如下:

 

 

                                        


注意:其中的“com.aidl.IPerson”是客户端用于访问AIDL服务的ID。

 

 

至此服务端的AIDL服务编写完成,接下来进行客户端代码的编写,新建工程,将服务端的自动生成的

 

IPerson.java文件连同包目录一起复制到客户端工程中,如下图:

 

 

 

 

以下程序实现了绑定AIDL服务,以及获取服务端数据:

 

 

public class MainActivity extends Activity implements OnClickListener{private Button btn_aidl;private Button btn_get;private TextView tv_show;private Intent mIpItent;private IPerson mIpIPerson=null;private ServiceConnection conn=new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mIpIPerson=IPerson.Stub.asInterface(service);btn_get.setEnabled(true);}};    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initData();        initView();        initEvent();    }        private void initData(){    mIpItent=new Intent("com.aidl.IPerson");    }    private void initView(){    btn_aidl=(Button) this.findViewById(R.id.btn_aidl);    btn_get=(Button) this.findViewById(R.id.btn_get);    tv_show=(TextView) this.findViewById(R.id.tv_show);    btn_get.setEnabled(false);    }           private void initEvent(){    btn_aidl.setOnClickListener(this);    btn_get.setOnClickListener(this);    }    @Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_aidl://绑定AIDL服务bindService(mIpItent, conn, Context.BIND_AUTO_CREATE);break;case R.id.btn_get://获取服务端数据try {tv_show.setText("姓名:"+mIpIPerson.getName()+"\n年龄:"+mIpIPerson.getAge());} catch (RemoteException e) {e.printStackTrace();}default:break;}}}

 

 

 

 

 

 

以上代码使用bindService方法来绑定AIDL服务,其中需要指定AIDL服务的ID,也就是标签中的

 

android:name属性值。在绑定时需要一个ServiceConnection对象,当绑定成功,系统调用

 

ServiceConnection.onServiceConnected方法,通过此方法的service参数获取AIDL服务对象。最后先运行服务端程

 

序,再运行客户端程序。

 

效果如下:

 

 

传递复杂数据的AIDL服务

 

AIDL服务只支持有限的数据类型,因此,如果用AIDL服务传递一些复杂的数据需要做更一步处理,AIDL服务支

 

持的数据类型如下。

 

(1)java的简单类型(int、char、boolean等),不需要导入。

 

(2)String和CharSequence,不需要导入。

 

(3)List和Map,List和Map对象的元素类型必须是AIDL服务支持的数据类型,不需要导入。

 

(4)AIDL自动生成的接口,需要导入。

 

(5)实现android.os.Parcelable接口的类,需要导入。

 

以下程序传递的数据类型是Person类,服务端代码如下:

 

(1)新建Person实现Parcelable接口

 

 

public class Person implements Parcelable{private String name;private int age;public static final Parcelable.Creator CREATOR=new Creator() {@Overridepublic Person[] newArray(int size) {return new Person[size];}@Overridepublic Person createFromParcel(Parcel source) {return new  Person(source.readInt(),source.readString());}};public Person(){}public Person(int age,String name){this.name=name;this.age=age;}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(age);dest.writeString(name);}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;}}

 

 

 

 

 

Person实现android.os.Parcelable这个接口,该接口用于序列化对象,在Person类中必须有一个静态常量,常量

 

名必须是CREATOR,而且CREATOR常量的数据类型必须是Parcelable.Creator。在writeToParcel方法中需要将序列

 

化的值写入Parcel对象,注意,读取的顺序必须和写入的顺序保持一致

 

(2)接着建立一个IPerson.aidl文件,代码如下:

 

 

package com.aidl;import com.aidl.Person;interface IPerson{Person getPerson();}

 

 

 

 

 

(3)建立一个Person.aidl文件,代码如下:

 

package com.aidl; parcelable Person;

 

 

 

 

 

 

(4)创建一个MyService类,代码如下:

 

 

public class MyService extends Service {public class PersonImpl extends IPerson.Stub {@Overridepublic Person getPerson() throws RemoteException {Person person = new Person();person.setName("bill");person.setAge(25);return person;}}@Overridepublic IBinder onBind(Intent intent) {return new PersonImpl();}}

 

 

 

 

 

最后服务端的工程目录结构如下图:

 

 

 

OK,服务端的AIDL服务编写完毕,接着编写客户端程序,将服务端的Person.java与IPerson.aidl连同包一起复

 

制到客户端工程中,如下图:

 

 

 

以下代码实现了获取服务端的Person对象中的数据:

 

 

public class MainActivity extends Activity implements OnClickListener{private Button btn_aidl;private Button btn_get;private TextView tv_show;private Intent mIpItent;private IPerson mIpIPerson=null;private ServiceConnection conn=new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mIpIPerson=IPerson.Stub.asInterface(service);btn_get.setEnabled(true);}};    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initData();        initView();        initEvent();    }        private void initData(){    mIpItent=new Intent("com.bill.aidl.IPerson");    }    private void initView(){    btn_aidl=(Button) this.findViewById(R.id.btn_aidl);    btn_get=(Button) this.findViewById(R.id.btn_get);    tv_show=(TextView) this.findViewById(R.id.tv_show);    btn_get.setEnabled(false);    }           private void initEvent(){    btn_aidl.setOnClickListener(this);    btn_get.setOnClickListener(this);    }    @Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_aidl://绑定AIDL服务bindService(mIpItent, conn, Context.BIND_AUTO_CREATE);break;case R.id.btn_get://获取服务端数据try {Person person=mIpIPerson.getPerson();tv_show.setText("姓名:"+person.getName()+"\n年龄:"+person.getAge());} catch (RemoteException e) {e.printStackTrace();}default:break;}}}

 

 

 

 

 

先运行服务端程序,在运行客户端程序,运行效果如下:

 

 

 

 

 

 

 

 

-------------------------------------------------------------------------------------------------------------------------------------------------------

转载请注明出处:http://blog.csdn.net/hai_qing_xu_kong/article/details/47748779情绪控

 

 

 

 

更多相关文章

  1. Flex开发Android(安卓)更改ViewMenu外观
  2. Netty 长连接服务
  3. 微信Android客户端架构演进之路-简单总结
  4. 编译可在Android上运行的可执行文件:C/C++交叉编译环境
  5. Android最简单的基于FFmpeg的例子(四)---以命令行的形式来使用ff
  6. 史上最易懂的Android(安卓)jni开发资料--NDK环境搭建
  7. [Android(安卓)UI] shape和selector的结合使用
  8. Android(安卓)多渠道打包提速
  9. [Android(安卓)Studio] Gradle fails to resolve dependencies i

随机推荐

  1. 【mysql 优化 5】左连接和右连接优化
  2. 数据库相关零散知识点记录
  3. mysql 反向生成 er图
  4. 用过mysql存储过程和oracle存储过程的哥
  5. mysql 拷贝表(复制表)的几种方式
  6. [mysql] 一次sql耗时高引发报警的分析和
  7. MySQL 慢查询日志分析及可视化结果
  8. MySQL 自定义函数.txt
  9. 救急~mysql无法启动,显示[ERROR] Aborting
  10. MySQL 绿色版基本设置语句