Android--Service之AIDL传递系统基本类型数据

前言

  前面讲解了Service的一些基本内容。但是对于绑定服务传递数据,只局限于本地服务,无法使用服务进行跨进程间的交互。如果需要用到跨进程交互的话,需要用到一个新的技术-AIDL,这篇博客就针对AIDL如何传递内置类型数据进行讲解。对于Service不熟悉的朋友,可以先看看之前的博客:Service基础Service高级Service应用

  本篇博客内容如下:

  1. 什么是ADIL?
  2. 如何定义AIDL?
  3. ADIL做了什么?
  4. 使用ADIL传递系统基本数据

 

什么是AIDL?

  先来回顾一下,Android在本地的Service中如何与其它组件进行交互的,首先Service必须实现其onBind()方法,然后在onBind方法传递一个IBinder接口的实现,而在其它组件中使用bindService()绑定一个服务,再通过其中的参数ServiceConnection对象获取到Service中定义的IBinder接口的实现。那么与Service进行数据交互,其实就是传递一个IBinder,通过这个IBinder进行交互。

  而现在就碰到一个问题,在同一个进程中,是可以获取到这个Service类的,也就可以获得这个Service中定义的IBinder,但是如果在不同的应用中,即远程服务,如何获取IBinder呢?仅仅是在不同的应用定义一相同的类是没有用的,所以Android为我们提供了AIDL语言,它需要先定义一个远程调用接口,然后为该接口提供一个实现类,通过共享这个远程调用接口来达到进程间数据交互的目的,而这个接口的代码是有很多共性的,并且编写过程相当枯燥乏味,所以Android开发者为我们提供了ADIL来简化通讯接口的开发。

  AIDL(Android Interface Definition Language)是Android远程调用接口的定义语言。它有它自己的一套语法规范,但是和Java类似,这并不难理解,详细的这个会后面介绍。而当你定义好一个AIDL接口之后,你会发现在gen/目录下,多出一个与定义的AIDL包名相同,文件名相同的一个Java类,这个类是编译器根据定义的AIDL接口自动生成的代码,观察之后发现其实它也是继承了Binder类(Binder是IBinder的实现类),所以它可以通过ServiceConnection进行数据传递。Service只需要暴露这个AIDL接口给客户端,让客户端也定义它,这样两个应用进程就可以通讯了。

 

如何定义AIDL?

  AIDL的语法与Java接口的语法非常相似,但是存在一些差异:

  1. AIDL定义接口的源代码后缀必须以.aidl结尾。
  2. AIDL一样要指定AIDL接口的包信息package *。
  3. AIDL接口无需指定public、private、protected等作用域,可以理解为就是public。
  4. AIDL默认情况下只能传递基本类型、String、List、Map、CharSequence。
  5. 如果需要传递其他类型的对象,需要import对象的包名,并需要对对象进行特殊处理(之后会介绍)。

  例如:

1 package com.example.aidlservicedemo.domain;
2 
3 interface IDog{
4     String getName();
5     int getAge();    
6 }

 

ADIL做了什么?

  当你声明完一个AIDL接口的时候,你会发现在项目的gen/目录下,对应包中存在一个同名的Java文件,这个文件是Android帮我们自动生成的,里面有很多代码,这里只讲一下需要注意的。查看自动生成的这个Java文件代码,会发现它定义了一个名为Stub的静态抽象类,这个Stub继承了Binder,实现了AIDL接口,当然其中也实现了AIDL接口的两个方法,粗略看一下会发现它对数据做了一个序列化和反序列化的操作。正因为AIDL对数据进行了序列化和反序列化,所以才可以在进程间传递。

  

使用ADIL传递系统基本数据

  定义好AIDL接口之后,就需要通过服务把接口暴露给客户端,这里Service.onBind()传递的就是这个Stub静态抽象类的实现类,其他没什么特别的。

  下面通过一个Demo来演示ADIL如何传递数据的,在示例中,给出两个应用,分别实现Server与调用客户端,使用的AIDL接口就是上面给出的AIDL示例代码,这里不再重复定义。

  AIDL服务:BaseTypeService.java

 1 package com.example.aidlservicedemo;
 2 
 3 import java.util.Random;
 4 
 5 import com.example.aidlservicedemo.domain.IDog.Stub;
 6 
 7 import android.app.Service;
 8 import android.content.Intent;
 9 import android.os.IBinder;
10 import android.os.RemoteException;
11 import android.util.Log;
12 
13 public class BaseTypeService extends Service {
14     private final String TAG="main";
15     private DogBinder binder=null;
16     private String[] names=new String[]{"小白","旺财","小黑"};
17     private int[] ages=new int[]{1,2,3};
18     
19     /**
20      * Stub的实现类,Stub内部实现了Binder
21      * 内部实现AIDL定义的方法
22      */
23     public class DogBinder extends Stub{
24 
25         @Override
26         public String getName() throws RemoteException {
27             Random random=new Random();
28             int nextInt = random.nextInt(2);            
29             return names[nextInt];
30         }
31 
32         @Override
33         public int getAge() throws RemoteException {
34             Random random=new Random();
35             int nextInt = random.nextInt(2);            
36             return ages[nextInt];
37         }        
38     }
39     
40     @Override
41     public void onCreate() {
42         super.onCreate();
43         // 实例化Binder对象
44         binder=new DogBinder();
45         Log.i(TAG, "创建服务成功");
46     }
47 
48     @Override
49     public IBinder onBind(Intent intent) {
50         Log.i(TAG, "绑定服务成功");
51         // 返回Binder对象
52         return binder;
53     }
54 }

  客户端调用服务获取数据: 

  1 package com.example.aidlClientdemo;
  2 
  3 import com.example.aidlservicedemo.domain.IDog;
  4 import android.app.Activity;
  5 import android.content.ComponentName;
  6 import android.content.Intent;
  7 import android.content.ServiceConnection;
  8 import android.os.Bundle;
  9 import android.os.IBinder;
 10 import android.view.View;
 11 import android.view.View.OnClickListener;
 12 import android.widget.Button;
 13 import android.widget.Toast;
 14 
 15 public class BaseTypeActivity extends Activity {
 16     private Button btn_startService, btn_endService,btn_getServiceData;
 17     private IDog dogService;
 18     
 19     @Override
 20     protected void onCreate(Bundle savedInstanceState) {
 21         super.onCreate(savedInstanceState);
 22         setContentView(R.layout.activity_service);
 23 
 24         btn_startService = (Button) findViewById(R.id.btn_startService);
 25         btn_endService = (Button) findViewById(R.id.btn_endService);
 26         btn_getServiceData = (Button) findViewById(R.id.btn_getServiceData);
 27 
 28         btn_startService.setOnClickListener(click);
 29         btn_endService.setOnClickListener(click);
 30         btn_getServiceData.setOnClickListener(click);
 31     }
 32 
 33     private View.OnClickListener click = new OnClickListener() {
 34 
 35         @Override
 36         public void onClick(View v) {
 37             switch (v.getId()) {
 38             case R.id.btn_startService:
 39                 startService();
 40                 break;
 41             case R.id.btn_endService:
 42                 endService();
 43                 break;
 44             case R.id.btn_getServiceData:
 45                 getServiceDate();
 46                 break;
 47             }
 48         }                
 49     };
 50     /*
 51      * 获取数据
 52      */
 53     private void getServiceDate() {
 54         try {
 55             if(dogService!=null){
 56                 StringBuilder sBuilder=new StringBuilder();
 57                 sBuilder.append("name:"+dogService.getName());
 58                 sBuilder.append("\nage:"+dogService.getAge());
 59                 Toast.makeText(BaseTypeActivity.this, sBuilder.toString(), Toast.LENGTH_SHORT).show();
 60             }
 61             else
 62             {
 63                 Toast.makeText(BaseTypeActivity.this, "请先绑定服务", Toast.LENGTH_SHORT).show();
 64             }
 65         } catch (Exception e) {
 66             e.printStackTrace();
 67         }        
 68     }
 69 
 70     private ServiceConnection connBase=new ServiceConnection() {
 71         
 72         @Override
 73         public void onServiceDisconnected(ComponentName name) {
 74             dogService=null;
 75         }
 76         
 77         @Override
 78         public void onServiceConnected(ComponentName name, IBinder service) {
 79             // IDog.Stub.asInterface,获取接口
 80             dogService=IDog.Stub.asInterface(service);
 81         }
 82     };
 83     
 84     /**
 85      * 开始服务
 86      */
 87     private void startService(){
 88         Intent intent=new Intent();
 89         intent.setAction("cn.bgxt.Service.BASE_TYPE_SERVICE");
 90         bindService(intent, connBase, BIND_AUTO_CREATE);
 91         Toast.makeText(BaseTypeActivity.this, "开始绑定服务", Toast.LENGTH_SHORT).show();
 92     }
 93     /**
 94      * 停止服务
 95      */
 96     private void endService(){
 97         if(connBase!=null)
 98         {
 99             unbindService(connBase);
100             // 接触绑定的时候需要回收dogService连接资源
101             // 在源码中漏了,这是后来加上的
102             dogService=null;
103             Toast.makeText(BaseTypeActivity.this, "服务解除绑定", Toast.LENGTH_SHORT).show();
104         }
105     }    
106 }

 

  效果展示:先运行服务应用,再运行客户端应用。

 

   源码下载

 

总结

  本篇博客只介绍了AIDL的基本结构,以及如何通过AIDL接口传递一个系统内置类型的数据。下一篇博客将介绍一下AIDL的高级应用,如何传递一个自定义对象。

 

posted @ 2013-11-11 07:23  承香墨影  阅读(5878)  评论(4编辑  收藏  举报