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的高級應用,如何傳遞一個自定義對象。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM