Android 使用【AIDL】調用外部服務

在Android 中有一種服務說是服務其實倒不如說是一個接口,這個接口名爲:Android Interface Definition Language ,這個接口可提供跨進程訪問服務,英文縮寫爲:AIDL。

  此種服務的好處在於,多個應用程序之間建立共同的服務機制,通過AIDL在不同應用程序之間達到數據的共享和數據相互操作,下面將通過一個DEMO 演示AIDL 是如何爲應用程序之間提供服務的。

本文大綱爲:

  • 1、創建AIDL 服務端。
  • 2、創建AIDL 客戶端。
  • 3、客戶端調用服務端提供的服務接口。
  • 4、小結。

本文要實現的功能大致如下:創建AIDL服務端,此服務端將提供一個Student 的javabean 提供客戶端取得數據,因爲aidl 支持的數據類型比較簡單,故這裏建議把常用的數據類型的數據寫入服務。

1、創建AIDL 服務端

在Android 的src 文件夾下的任意包裏面新建文件,後綴名爲*.aidl,如下圖

輸入如下代碼:

 

package com.aidl.test;
import com.aidl.test.Student;

interface IMyService
{
        Map getMap(in String test_class,in Student student);
         Student getStudent();
}

 

Student 類是一個序列化的類,這裏使用Parcelable 接口來序列化是Google 提供的一個比Serializable 效率更高的序列化類。Student  類代碼如下:

 

package  com.aidl.test;

import  android.os.Parcel;
import  android.os.Parcelable;

public   class  Student  implements  Parcelable {

    
private   int  age;
    
private  String name;

    
public   int  getAge() {
        
return  age;
    }

    
public   void  setAge( int  age) {
        
this .age  =  age;
    }

    
public  String getName() {
        
return  name;
    }

    
public   void  setName(String name) {
        
this .name  =  name;
    }

    
public   static   final  Parcelable.Creator < Student >  CREATOR  =   new  Creator < Student > () {

        @Override
        
public  Student[] newArray( int  size) {
            
//  TODO Auto-generated method stub
             return   new  Student[size];
        }

        @Override
        
public  Student createFromParcel(Parcel source) {
            
//  TODO Auto-generated method stub
             return   new  Student(source);
        }
    };

    
public  Student() {
    }

    
public  Student(Parcel pl) {
        age 
=  pl.readInt();
        name 
=  pl.readString();
    }

    @Override
    
public   int  describeContents() {
        
//  TODO Auto-generated method stub
         return   0 ;
    }

    @Override
    
public   void  writeToParcel(Parcel dest,  int  flags) {
        
//  TODO Auto-generated method stub
        dest.writeInt(age);
        dest.writeString(name);
    }

}

 

 

在這裏必須注意,編寫javabean時必須注意如下三點:

  • 在Student 類中必須有一個靜態常量,常量名必須是CREATOR,而且CREATOR 常量的數據類型必須是 Parcelable.Creator
  • 在writeToParcel 方法中需要將要序列化的值寫入到 Parcel對象中。
  • 編寫完Student 爲時,必須再新建一個Student.aidl 文件,此文件輸入以下內容:
    parcelable Student; 這裏的書寫是供上面我們說過的接口   *.aidl 文件導包時可以找到,並通過此文件找到Student類對象。

如果上面的步驟順利通過的話,Android 將會自動在gen 目錄下R文件的相同目錄生成一個以*.aidl 文件命名的*.java 文件,如下圖:

順利生成成功後,我們再來編寫一個AIDL 服務類,代碼如下:

 

package  com.aidl.test;

import  java.util.HashMap;
import  java.util.Map;

import  android.app.Service;
import  android.content.Intent;
import  android.os.IBinder;
import  android.os.RemoteException;

public   class  MyService  extends  Service {

    @Override
    
public  IBinder onBind(Intent intent) {
        
//  TODO Auto-generated method stub
         return   new  MyServiceimpl();
    }

    
public   class  MyServiceimpl  extends  IMyService.Stub {

        @Override
        
public  Student getStudent()  throws  RemoteException {
            
//  TODO Auto-generated method stub
            Student st  =   new  Student();
            st.setAge(
18 );
            st.setName(
" terry " );

            
return  st;
        }

        @Override
        
public  Map getMap(String testClass, Student student)
                
throws  RemoteException {
            
//  TODO Auto-generated method stub
            Map < String, Object >  map  =   new  HashMap < String, Object > ();
            map.put(
" class " " 五年級 " );
            map.put(
" age " , student.getAge());
            map.put(
" name " , student.getName());
            
return  map;
        }

    }

}

 

 

如上代碼,MyService 服務類有一個子類並繼承自我們上面生成的*.java 文件重寫其中我們在*.aidl 中聲明的兩個接口方法,實現了其功能。上面IBinder 必須返回此服務類的子類對象,否則客戶端將無法獲得服務對象。

最後,即然有服務的操作,那麼就得在manifest文件中註冊服務類,代碼如下:

 

< service  android:name =".MyService" >
    
< intent-filter >
        
< action  android:name ="com.aidl.test.IMyService" ></ action >
    
</ intent-filter >
</ service >

 

 

至此,服務端就己經開發完成了,下面接着開發客啓端。

2、創建AIDL 客戶端

同樣是新建一個項目,這裏要注意,需要將服務端生成成功後的gen 目錄下的包複製過來,放到我們新建項目的src 文件夾下,如下圖:

因爲IMyService 這個生成類,引用到了Student 這個javabean 所以這裏一併將javabean也複製過來。

至此,客戶端的創建己經完畢,下面我們就要利用創建的客戶端去調用服務端的方法。

 

3、客戶端調用服務端提供的服務接口

先看一下運行效果:

細心的朋友會發現,上面的數據不是我們在上面客戶端爲Student 設置的數據嗎?怎麼在這個程序 裏面也同樣得到了?沒錯。這就是aidl 的魅力,下面來看看如何調用 吧,圖中有兩個按鈕,一個按鈕爲綁定AIDL 服務,即通過Activity 的 bindService 綁定 AIDL 外部服務,全部代碼如下:

 

package  com.aidl.client;

import  com.aidl.test.IMyService;

import  android.app.Activity;
import  android.app.AlertDialog;
import  android.content.ComponentName;
import  android.content.Context;
import  android.content.Intent;
import  android.content.ServiceConnection;
import  android.os.Bundle;
import  android.os.IBinder;
import  android.os.RemoteException;
import  android.view.View;
import  android.view.View.OnClickListener;
import  android.widget.Button;

public   class  aidlActivity  extends  Activity  implements  OnClickListener {
    Button btn1, btn2;

    
private  IMyService myService  =   null ;
    
private  ServiceConnection serviceConnection  =   new  ServiceConnection() {

        @Override
        
public   void  onServiceDisconnected(ComponentName name) {
            
//  TODO Auto-generated method stub

        }

        @Override
        
public   void  onServiceConnected(ComponentName name, IBinder service) {
            
//  TODO Auto-generated method stub
            myService  =  IMyService.Stub.asInterface(service);
            btn2.setEnabled(
true );

        }
    };

    
/**  Called when the activity is first created.  */
    @Override
    
public   void  onCreate(Bundle savedInstanceState) {
        
super .onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btn1 
=  (Button) findViewById(R.id.Button01);
        btn2 
=  (Button) findViewById(R.id.Button02);
        btn2.setEnabled(
false );

        btn1.setOnClickListener(
this );
        btn2.setOnClickListener(
this );
    }

    @Override
    
public   void  onClick(View v) {
        
//  TODO Auto-generated method stub
         switch  (v.getId()) {
        
case  R.id.Button01:
            bindService(
new  Intent( " com.aidl.test.IMyService " ),
                    serviceConnection, Context.BIND_AUTO_CREATE);
            
break ;
        
case  R.id.Button02:
            StringBuilder sb 
=   new  StringBuilder();
            
try  {
                sb.append(
" 學生名稱爲: "   +  myService.getStudent().getName()  +   " /n " );
                sb.append(
" 年齡爲: "   +  myService.getStudent().getAge()  +   " /n " );
                sb.append(
" map 對象內容爲如下: "
                        
+  myService.getMap( " 中國 " , myService.getStudent())
                                .toString());
            } 
catch  (RemoteException e) {
                
//  TODO Auto-generated catch block
                e.printStackTrace();
            }

            
new  AlertDialog.Builder(aidlActivity. this ).setTitle( " 調用外部服務 " )
                    .setMessage(sb.toString()).setPositiveButton(
                            android.R.string.ok, 
null ).show();
            
break ;
        
default :
            
break ;
        }
    }
}

 

 

在ServiceConnetction裏面對IMyService 進行初始化,即可操作該對象 ,該對象就可以得到我們所有要處理的數據。

 

4、小結

  • aidl 文件調用javabean 的aidl文件必須導包;
  • javabean 必須序列化,如果沒有用javabean可以用簡單的變量代替,如返回一個整型,返回一個字符串等。
  • 使用aidl 必須同時存在客戶端和服務端,即客戶端在本機上,服務端也在本機上,要使用客戶端必須服務端事先在本機上註冊過服務。

代碼下載:服務端DEMO
     客戶端DEMO

 


 

轉帖自:http://www.cnblogs.com/TerryBlog/archive/2010/08/24/1807605.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章