初次发帖,对Android了解和掌握还不是很深,敬请各位指正交流,一起进步。

Android为了实现进程间通信,提供了AIDL机制。AIDL全称是Android Interface Definition Language,即进程间接口描述语言。通过AIDL机制,应用程序可以通过描述的接口访问远程服务中的方法。

下面说一下AIDL机制的使用方法,因为自身水平问题,范例都比较简单。

Server端与Client端功能简介:

Server端:在Server端开启一个后台服务, 该服务只提供两种方法供调用

1、int型的getNumber(int)方法,该方法将客户端传递过来的数据加3,再返回给客户端。

2、void型的setNumber()方法,该方法是设置Service中的变量为客户端传递进来的数据。

Client端:Activity,主要有两个按钮,一个是调用按钮,读取远程Service中的数据,一个是设置按钮,将Client端EditText中的数值传递给远程Service。

Service端与Client端的交互逻辑如下:

Server端负责后台Service的开启与中止,Client端开启后,首先判断服务是否存在,若存在则可以通过AIDL机制调用远程Service提供的方法并设置远程Service中的全局变量,若服务不存在则不可调用(本人在此处一个不经意的错误,排查了很长时间,在后面说)

使用AIDL方法实现上述功能的主要步骤如下:

一、AIDL接口定义:

在本步骤中,定义的是接口的名称以及方法的参数、返回值,新建一个.aidl文件,文件名需要与接口名相同。本范例中AIDL定义如下:

package com.example.servicedemo;interface IGetNumber{int getNumber();void setNumber(int i);}


二、在Service中实现定义的AIDL接口

定义完AIDL后,在gen包中,会自动生成一个与AIDL同名的.java文件,即依据所定义的接口自动生成的一个接口文件,该文件包含一个Stub抽象类,该抽象类又包含了我们在AIDL中定义的方法,Stub抽象类继承了Binder,Activity是通过Binder机制来实现与Service通信的,因此我们需要在Service中实现该Stub抽象类,以具体实现在AIDL中定义的方法,这样在Client端绑定远程Service时通过返回一个stub类可以调用Service的方法。

Service端的主要代码如下:

public class ServiceDemo extends Service{public  int num=0;public Stub getNumber=new MyBinder();@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn getNumber;}public class MyBinder extends IGetNumber.Stub{@Overridepublic int getNumber() throws RemoteException {// TODO Auto-generated method stubnum=num+3;return num;}@Overridepublic void setNumber(int i) throws RemoteException {// TODO Auto-generated method stubnum=i;}}

三、Client端绑定远程Service


Client端首先需要导入Server端gen文件夹下生成的IGetNumber.java文件,具体的方法为在Client端src文件夹下新建一个与Server端同名的包,并将IGetNumber.java复制到该包下。Client端Activity主要代码如下:

1、首先判断远程Service是否开启,此处与本文关系不大,一并贴一下。该功能是通过ActivityManager实现的,ActivityManager类中有一个getRunningServices(int MaxNum)方法,该方法可以返回一个正在运行的服务的列表,参数定义了返回的列表中列表项的最大数目。该判断过程放在onCreate()方法中,主要代码如下:

         public List <ActivityManager.RunningServiceInfo> mList;public ActivityManager mAcManager;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);if (savedInstanceState == null) {getSupportFragmentManager().beginTransaction().add(R.id.container, new PlaceholderFragment()).commit();}findView();         //获取控件变量的函数mAcManager=(ActivityManager)getSystemService(ACTIVITY_SERVICE);mList=mAcManager.getRunningServices(30);if(ServiceIsExist(mList,ServiceName)){Toast.makeText(getApplicationContext(), "远程服务已经开启", 0).show();}else{Toast.makeText(getApplicationContext(), "远程服务尚未开启", 0).show();}}


ServiceIsExist(mList,ServiceName)即为判断一个服务是否存在的函数,返回一个Boolean型,具体代码为:

private boolean ServiceIsExist(List<RunningServiceInfo> servicelist,String classname ) {// TODO Auto-generated method stubfor(int i=0;i<servicelist.size();i++){if(classname.equals(servicelist.get(i).service.getClassName())){return true;}}return false;}

2、绑定远程Service,该步骤需要通过之前导入的IGetNumber.java对象和一个ServiceConnection对象实现。主要代码如下,其中btn_start即为开始调用的按钮:

private IGetNumber igetNumber=null;public ServiceConnection servConn;         btn_start.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {// TODO Auto-generated method stubservConn=new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubigetNumber=IGetNumber.Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stubigetNumber=null;}};Intent intent=new Intent(IGetNumber.class.getName());bindService(intent, servConn, 0);if(igetNumber!=null){try {Toast.makeText(getApplicationContext(),String.valueOf(igetNumber.getNumber()),0).show();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}});

需要特别注意的是,在bindService()函数的第三个参数中,本人吃了大亏。由于自己的大意,第三个参数我写的是Context.BIND_AUTO_CREATE,由于本文的应用场景是远程服务不开启则无法调用,因此在测试的时候发现即使Server端关闭了Client端仍旧可以调用AIDL中定义的方法,即使调用了Unbind()方法和onDestroy()方法。这显然是不对的,经过仔细的研究才发现,BIND_AUTO_CREATE的意义在于,若绑定的Service不存在则自动创建一个Service实例,因此即使通过Server端将开启的Service解除绑定并销毁,Client端仍然可以在系统内实例化一个远程Service并绑定。排查过后改为0,问题就解决了,此处花了好几个小时,新手学艺不精,长教训了。有此应用需求的朋友一定要注意。

通过Toast.makeText(getApplicationContext(),String.valueOf(igetNumber.getNumber()),0).show(),我们成功的通过AIDL方式调用了远程Service中的方法,并将返回值以Toast的方式显示在了客户端界面中。

还要再说一点的是,众所周知,onCreate()函数只在Activity创建的过程中调用一次,而本文中需要绑定的远程Service不一定开启,因此我没有将绑定远程Service的代码放在onCreate()函数中,而是放在了“开始调用”按钮的点击事件响应代码中,这样做不好的地方就是如果远程Service已经开启,则Activity创建后需要点击两次才能真正的开始调用AIDL中定义的方法

3、设置远程Service中的全局变量,即实现AIDL中定义的setNumber(int )方法。上一步实现之后,这一步就非常简单了,直接贴代码:

btn_set.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {// TODO Auto-generated method stubtry {igetNumber.setNumber(Integer.parseInt(edt_input.getText().toString()));} catch (NumberFormatException | RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});


在有些应用场景中,需要将参数传递给远程Service进行处理,实际上该方法就是演示这样一个过程。

四、Manifest文件中对远程Service的定义

这一步就比较简单了,需要注意的是在对Service定义的时候,android:process参数需要设置为":remote"

经过以上步骤,基本就可以通过AIDL的方式来调用远程Service提供的方法了。

更多相关文章

  1. 认识Android中的双向绑定
  2. 自定义实现简单的Android颜色选择器(附带源码)
  3. Android自定义Toast的时长、位置、及显示的View
  4. Mars Android视频学习笔记——01_16_SQLite使用方法
  5. 使用shape来定义控件的一些显示属性
  6. Android 总结:进阶之路(资源与方法)
  7. android 自定义进度条颜色
  8. Android 关闭所有Activity完全退出程序方法
  9. android 图文列表的实现方法

随机推荐

  1. Zipalign——Android(安卓)apk优化工具
  2. s3c2410/2440(armv4t) 移植android
  3. Android对kernel增加的:Early suspend, La
  4. Ice Cream Sandwich 邀请函:10 月 19 号,香
  5. Android使用Service实现简单音乐播放实例
  6. Intent的用法(初步)
  7. 从零开始学编程——环境配置
  8. Android之自定义各种控件
  9. [Android] ProcessBuilder与Runtime.getR
  10. Android(安卓)UI开发第二十九篇――Andro