深刻解析 Android 的 AIDL 介面
来源:互联网 发布:旋风十一人网络播放量 编辑:程序博客网 时间:2024/06/08 13:49
在Android應用框架裡,應用層級的軟體大多是Java類別,而系統層級的軟體大多是C或 C++類別。Android使用JNI介面來達成這個目標。例如,在Android裡有個MediaPlayer.cpp類別,當它搭配上JNI介面之後,在VM上執行的MediaPlayer.java就可以透過JNI介面與MediaPlayer.cpp類別溝通了。 圖1-1 基於這樣的架構,我門就可以盡量將MediaPlayer.java裡的程式邏輯移入MediaPlayer.cpp類別裡,以便加快程式的執行速度。此外,以JNI介面包裝MediaPlayer.cpp類別,並且銜接相互輝映的MediaPlayer.java類別,可以讓眾多的Java應用程式透過MediaPlayer.java來使用MediaPlayer.cpp類別的服務。這是一種非常有用的包裝技巧,藉由包裝來創造更多的應用機會。 為了進一步創造更多的應用機會,可以替MediaPlayer.java類別加上AIDL介面,讓更多的Java應用程式能與MediaPlayer.java類別進行遠距的IPC溝通。如下圖所示: 圖1-2 上圖表示出JNI在Android裡扮演的角色,以及Android框架裡Java與C/C++類別融合的基本架構。上面的圖1-2是一個較為抽象的圖,凸顯JNI與AIDL的相互呼應之角色。 於此,以高煥堂所寫的第2本Android書:<<Android 軟體架構設計>> 一書裡的範例:HalfAdder組件為例,展示其幕後的細節架構。首先看看其JNI介面之上的細節架構,如下UML圖: 圖1-3 上圖1-2幕後的細節架構之一 上圖凸顯了AIDL介面的細節架構。下圖1-4將換個角度,從*.so開發者來看,當我們開發系統層級的C/C++類別時,也能善用JNI,創造C/C++類別的廣大商機。其細節架構如下UML圖: 圖1-4 上圖1-2幕後的細節架構之二 1.3 說明C/C++組件開發 從上圖1-4可看到此範例的C/C++組件部份。其詳細的程式碼,請閱讀高煥堂所寫的第2本Android書:<<Android 軟體架構設計>> 一書之第5~6章。 1.4 說明AIDL介面類別之開發 基於剛才所撰寫的相對應Java類別:Calculator.java,就能順利配上AIDL介面了。 1.4.1 細說AIDL介面與IBinder介面 其實,AIDL介面幕後是仰賴著IBinder介面的。所以,我們的應用程式可以選擇使用IBinder介面,也可以使用AIDL介面。如果採取IBinder介面,就不必使用aidl.exe工具去產出calInterface.java介面定義檔了,其介面類別較單純一些,如下圖所示: 圖1-5 僅使用較單純的IBinder介面 由於IBinder介面只提供單一函數(即transact()函數)來進行遠距溝通,呼叫起來比較不方便。例如,當Calculator類別有多個函數時,myActivity要如何呼叫它們呢? 可以呼叫IBinder介面的transact()函數,再轉而呼叫Calculator的各個函數。由於它並不太方便,所以Android提供Proxy/Stub結構的AIDL介面來化解這個問題,其架構圖如下: 圖1-6 更方便的AIDL介面(其介面類別結構較複雜一些) 在本範例裡,將採取AIDL介面,同時也介紹其幕後的IBinder介面,以及其兩這之間的密切關係。 1.4.2 細說Stub類別的程式碼 這個Stub類別就是由aidl.exe所產出的;也就是在calInterface.java裡面。茲再重複列出calInterface.java程式碼如下: /*---- calInterface.java ----*/ /* * This file is auto-generated. DO NOT MODIFY. * Original file: calInterface.aidl */ package com.misoo.gx06; import java.lang.String; import android.os.RemoteException; import android.os.IBinder; import android.os.IInterface; import android.os.Binder; import android.os.Parcel; public interface calInterface extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.misoo.gx06.calInterface { private static final java.lang.String DESCRIPTOR = "com.misoo.gx06.calInterface"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an calInterface interface, * generating a proxy if needed. */ public static com.misoo.gx06.calInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } com.misoo.gx06.calInterface in = (com.misoo.gx06.calInterface)obj.queryLocalInterface(DESCRIPTOR); if ((in!=null)) { return in; } return new com.misoo.gx06.calInterface.Stub.Proxy(obj); } public android.os.IBinder asBinder() { return this; } public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throwsandroid.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_EvDigitPress: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); java.lang.String _result = this.EvDigitPress(_arg0); reply.writeNoException(); reply.writeString(_result); return true; } case TRANSACTION_EvCPress: { data.enforceInterface(DESCRIPTOR); java.lang.String _result = this.EvCPress(); reply.writeNoException(); reply.writeString(_result); return true; } case TRANSACTION_EvPlusPress: { data.enforceInterface(DESCRIPTOR); java.lang.String _result = this.EvPlusPress(); reply.writeNoException(); reply.writeString(_result); return true; } case TRANSACTION_EvAssignPress: { data.enforceInterface(DESCRIPTOR); java.lang.String _result = this.EvAssignPress(); reply.writeNoException(); reply.writeString(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.misoo.gx06.calInterface { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } public java.lang.String EvDigitPress(int d) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.String _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(d); mRemote.transact(Stub.TRANSACTION_EvDigitPress, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public java.lang.String EvCPress() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.String _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_EvCPress, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public java.lang.String EvPlusPress() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.String _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_EvPlusPress, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public java.lang.String EvAssignPress() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.String _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_EvAssignPress, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_EvDigitPress = (IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_EvCPress = (IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_EvPlusPress = (IBinder.FIRST_CALL_TRANSACTION + 2); static final int TRANSACTION_EvAssignPress = (IBinder.FIRST_CALL_TRANSACTION + 3); } public java.lang.String EvDigitPress(int d) throws android.os.RemoteException; public java.lang.String EvCPress() throws android.os.RemoteException; public java.lang.String EvPlusPress() throws android.os.RemoteException; public java.lang.String EvAssignPress() throws android.os.RemoteException; } 這個calInterface.java檔案是由aidl.exe工具程式所產出的。 首先,calInterface介面繼承了Android提供的IInterface介面,如下述程式碼: public interface calInterface extends android.os.IInterface { ……… } 這個類別定義又內含有一個Stub類別,其繼承Android提供的Binder父類別,而且實作calInterface介面,如下述程式碼: public interface calInterface extends android.os.IInterface { ………. public static abstract class Stub extends android.os.Binder implements com.misoo.gx06.calInterface { ………. private static class Proxy implements com.misoo.gx06.calInterface { ……… } ……….. } 由於Stub類別繼承了Binder父類別,而Binder又實作了IBinder介面,所以Stub類別支持兩個介面:IBinder和calInterface。其內含的Proxy類別也支持calInterface。 圖1-7 IBinder與calInterface介面之關係 1.4.4 細說CalBinder類別的程式碼 基於這個結構,就可以從Stub類別衍生(Derive)出子類別:calBinder,其程式碼為: /*---- CalBinder.java ----*/ package com.misoo.gx06; import android.os.RemoteException; public class CalBinder extends calInterface.Stub{ private Calculator mCal = null; public CalBinder(){ mCal = new Calculator(); } @Override public String EvAssignPress() throws RemoteException { mCal.EvAssignPress(); return mCal.retStr; } @Override public String EvCPress() throws RemoteException { mCal.EvCPress(); return mCal.retStr; } @Override public String EvDigitPress(int d) throws RemoteException { mCal.EvDigitPress(d); return mCal.retStr; } @Override public String EvPlusPress() throws RemoteException { mCal.EvPlusPress(); return mCal.retStr; } } 其中,指令: public CalBinder(){ mCal = new Calculator(); } 誕生了一個Calculator物件,如此與Calculator類別銜接起來了。 1.4.5 函數呼叫的情境 此範例程式需要用到各AIDL類別的詳細函數如下圖所示: 圖1-8 AIDL各類別裡的函數及其關係 只要對物件觀念和技術較為熟悉的話,就可看出來其並不太複雜,只是基本物件觀念之應用而已。更詳細之說明,請看高煥堂所寫的第2本Android書:<<Android 軟體架構設計>> 一書。
- 深刻解析 Android 的 AIDL 介面
- 深刻解析 Android 的 AIDL 介面
- 深刻解析 Android 的 AIDL 介面
- 深刻解析 Android 的 AIDL
- 深刻解析 Android 的 AIDL 界面(1)
- Android中aidl的解析和使用
- android Services AIDL 解析
- Android AIDL实例解析
- Android AIDL实例解析
- Android AIDL用法解析
- Android之AIDL使用解析
- Android AIDL机制范例解析
- 【Android进阶】-AIDL使用解析
- Android:Layout_weight的深刻理解
- Android:Layout_weight的深刻理解
- Android:Layout_weight的深刻理解
- Android:Layout_weight的深刻理解
- Android:layout_weight的深刻理解
- C中读取数组
- Ruby On Rails-2.0.2源代码分析(3)-resource
- 火车采集器简介
- Linux操作系统新贵MeeGo的前世与今生
- 2010年上半年工作总结
- 深刻解析 Android 的 AIDL 介面
- 过去几年的回顾&2010年关键词
- //刷新资源管理器
- IE在浏览PHP网页时总时提示下保存
- 如何转换NSString与NSDate?
- PHP 循环
- 深藏不露
- register_global=On,对安全有的影响
- mysql+php