編輯:Android開發實例
前言
前面講解了Service的一些基本內容。但是對於綁定服務傳遞數據,只局限於本地服務,無法使用服務進行跨進程間的交互。如果需要用到跨進程交互的話,需要用到一個新的技術-AIDL, 本文就針對AIDL如何傳遞內置類型數據進行講解。對於Service不熟悉的朋友,可以先看看之前的文章:http://www.fengfly.com/plus/view-214081-1.html 、http://www.fengfly.com/plus/view-214082-1.html、http://www.fengfly.com/plus/view-214084-1.html。
本文內容如下:
什麼是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接口的語法非常相似,但是存在一些差異:
例如:
- package com.example.aidlservicedemo.domain;
- interface IDog{
- String getName();
- int getAge();
- }
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
- package com.example.aidlservicedemo;
- import java.util.Random;
- import com.example.aidlservicedemo.domain.IDog.Stub;
- import android.app.Service;
- import android.content.Intent;
- import android.os.IBinder;
- import android.os.RemoteException;
- import android.util.Log;
- public class BaseTypeService extends Service {
- private final String TAG="main";
- private DogBinder binder=null;
- private String[] names=new String[]{"小白","旺財","小黑"};
- private int[] ages=new int[]{1,2,3};
- /**
- * Stub的實現類,Stub內部實現了Binder
- * 內部實現AIDL定義的方法
- */
- public class DogBinder extends Stub{
- @Override
- public String getName() throws RemoteException {
- Random random=new Random();
- int nextInt = random.nextInt(2);
- return names[nextInt];
- }
- @Override
- public int getAge() throws RemoteException {
- Random random=new Random();
- int nextInt = random.nextInt(2);
- return ages[nextInt];
- }
- }
- @Override
- public void onCreate() {
- super.onCreate();
- // 實例化Binder對象
- binder=new DogBinder();
- Log.i(TAG, "創建服務成功");
- }
- @Override
- public IBinder onBind(Intent intent) {
- Log.i(TAG, "綁定服務成功");
- // 返回Binder對象
- return binder;
- }
- }
客戶端調用服務獲取數據:
- package com.example.aidlClientdemo;
- import com.example.aidlservicedemo.domain.IDog;
- import android.app.Activity;
- import android.content.ComponentName;
- import android.content.Intent;
- import android.content.ServiceConnection;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.Toast;
- public class BaseTypeActivity extends Activity {
- private Button btn_startService, btn_endService,btn_getServiceData;
- private IDog dogService;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_service);
- btn_startService = (Button) findViewById(R.id.btn_startService);
- btn_endService = (Button) findViewById(R.id.btn_endService);
- btn_getServiceData = (Button) findViewById(R.id.btn_getServiceData);
- btn_startService.setOnClickListener(click);
- btn_endService.setOnClickListener(click);
- btn_getServiceData.setOnClickListener(click);
- }
- private View.OnClickListener click = new OnClickListener() {
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.btn_startService:
- startService();
- break;
- case R.id.btn_endService:
- endService();
- break;
- case R.id.btn_getServiceData:
- getServiceDate();
- break;
- }
- }
- };
- /*
- * 獲取數據
- */
- private void getServiceDate() {
- try {
- if(dogService!=null){
- StringBuilder sBuilder=new StringBuilder();
- sBuilder.append("name:"+dogService.getName());
- sBuilder.append("\nage:"+dogService.getAge());
- Toast.makeText(BaseTypeActivity.this, sBuilder.toString(), Toast.LENGTH_SHORT).show();
- }
- else
- {
- Toast.makeText(BaseTypeActivity.this, "請先綁定服務", Toast.LENGTH_SHORT).show();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- private ServiceConnection connBase=new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName name) {
- dogService=null;
- }
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- // IDog.Stub.asInterface,獲取接口
- dogService=IDog.Stub.asInterface(service);
- }
- };
- /**
- * 開始服務
- */
- private void startService(){
- Intent intent=new Intent();
- intent.setAction("cn.bgxt.Service.BASE_TYPE_SERVICE");
- bindService(intent, connBase, BIND_AUTO_CREATE);
- Toast.makeText(BaseTypeActivity.this, "開始綁定服務", Toast.LENGTH_SHORT).show();
- }
- /**
- * 停止服務
- */
- private void endService(){
- if(connBase!=null)
- {
- unbindService(connBase);
- // 接觸綁定的時候需要回收dogService連接資源
- // 在源碼中漏了,這是後來加上的
- dogService=null;
- Toast.makeText(BaseTypeActivity.this, "服務解除綁定", Toast.LENGTH_SHORT).show();
- }
- }
- }
效果展示:先運行服務應用,再運行客戶端應用。
源碼下載
總結
本文只介紹了AIDL的基本結構,以及如何通過AIDL接口傳遞一個系統內置類型的數據。下一篇將介紹一下AIDL的高級應用,如何傳遞一個自定義對象。
JSON代表JavaScript對象符號。它是一個獨立的數據交換格式,是XML的最佳替代品。本章介紹了如何解析JSON文件,並從中提取所需的信息。Android提供了四個
Android提供了許多方法來控制播放的音頻/視頻文件和流。其中該方法是通過一類稱為MediaPlayer。Android是提供MediaPlayer類訪問內置的媒體播放
JSON代表JavaScript對象符號。它是一個獨立的數據交換格式,是XML的最佳替代品。本章介紹了如何解析JSON文件,並從中提取所需的信息。Android提供了四個
今天模仿安卓QQ空間,效果如下: 打開程序的啟動畫面和導航頁面我就不做了,大家可以模仿微信的那個做一下,很簡單。這次主要做一下主頁面的實