• 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("
    age:"+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的高级应用,如何传递一个自定义对象。

  • 相关阅读:
    PHP xml_get_current_column_number() 函数
    PHP xml_get_current_byte_index() 函数
    PHP xml_error_string() 函数
    PHP utf8_encode() 函数
    PHP utf8_decode() 函数
    MySQL 资料库概论与MySQL 安装
    SEO之网站关键词的优化 :首页,内页关键字,长尾关键字
    前端开发chrome console的使用 :评估表达式 – Break易站
    chrome console的使用 : 异常和错误的处理 – Break易站
    SEO的基本概念 和 提交SITEMAP到搜索引擎
  • 原文地址:https://www.cnblogs.com/plokmju/p/android_Service_aidl_NormalType.html
Copyright © 2020-2023  润新知