Android應用框架裡,應用層級的軟體大多是Java類別,而系統層級的軟體大多是CC++類別。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

上圖表示出JNIAndroid裡扮演的角色,以及Android框架裡JavaC/C++類別融合的基本架構。上面的圖1-2是一個較為抽象的圖,凸顯JNIAIDL的相互呼應之角色。

於此,以高煥堂所寫的第2Android書:<<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++組件部份。其詳細的程式碼,請閱讀高煥堂所寫的第2Android書:<<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

*/

packagecom.misoo.gx06;

importjava.lang.String;

importandroid.os.RemoteException;

importandroid.os.IBinder;

importandroid.os.IInterface;

importandroid.os.Binder;

importandroid.os.Parcel;

publicinterfacecalInterfaceextendsandroid.os.IInterface

{

/** Local-side IPC implementation stub class. */

publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.misoo.gx06.calInterface

{

privatestaticfinaljava.lang.StringDESCRIPTOR= "com.misoo.gx06.calInterface";

/** Construct the stub at attach it to the interface. */

publicStub()

{

this.attachInterface(this,DESCRIPTOR);

}

/**

* Cast an IBinder object into an calInterface interface,

* generating a proxy if needed.

*/

publicstaticcom.misoo.gx06.calInterface asInterface(android.os.IBinder obj)

{

if((obj==null)) {

returnnull;

}

com.misoo.gx06.calInterface in = (com.misoo.gx06.calInterface)obj.queryLocalInterface(DESCRIPTOR);

if((in!=null)) {

returnin;

}

returnnewcom.misoo.gx06.calInterface.Stub.Proxy(obj);

}

publicandroid.os.IBinder asBinder()

{

returnthis;

}

publicbooleanonTransact(intcode, android.os.Parcel data, android.os.Parcel reply,intflags)throwsandroid.os.RemoteException

{

switch(code)

{

caseINTERFACE_TRANSACTION:

{

reply.writeString(DESCRIPTOR);

returntrue;

}

caseTRANSACTION_EvDigitPress:

{

data.enforceInterface(DESCRIPTOR);

int_arg0;

_arg0 = data.readInt();

java.lang.String _result =this.EvDigitPress(_arg0);

reply.writeNoException();

reply.writeString(_result);

returntrue;

}

caseTRANSACTION_EvCPress:

{

data.enforceInterface(DESCRIPTOR);

java.lang.String _result =this.EvCPress();

reply.writeNoException();

reply.writeString(_result);

returntrue;

}

caseTRANSACTION_EvPlusPress:

{

data.enforceInterface(DESCRIPTOR);

java.lang.String _result =this.EvPlusPress();

reply.writeNoException();

reply.writeString(_result);

returntrue;

}

caseTRANSACTION_EvAssignPress:

{

data.enforceInterface(DESCRIPTOR);

java.lang.String _result =this.EvAssignPress();

reply.writeNoException();

reply.writeString(_result);

returntrue;

}

}

returnsuper.onTransact(code, data, reply, flags);

}

privatestaticclassProxyimplementscom.misoo.gx06.calInterface

{

privateandroid.os.IBinder mRemote;

Proxy(android.os.IBinder remote)

{

mRemote = remote;

}

publicandroid.os.IBinder asBinder()

{

returnmRemote;

}

publicjava.lang.String getInterfaceDescriptor()

{

returnDESCRIPTOR;

}

publicjava.lang.String EvDigitPress(intd)throwsandroid.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;

}

publicjava.lang.String EvCPress()throwsandroid.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;

}

publicjava.lang.String EvPlusPress()throwsandroid.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;

}

publicjava.lang.String EvAssignPress()throwsandroid.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;

}

}

staticfinalintTRANSACTION_EvDigitPress= (IBinder.FIRST_CALL_TRANSACTION+ 0);

staticfinalintTRANSACTION_EvCPress= (IBinder.FIRST_CALL_TRANSACTION+ 1);

staticfinalintTRANSACTION_EvPlusPress= (IBinder.FIRST_CALL_TRANSACTION+ 2);

staticfinalintTRANSACTION_EvAssignPress= (IBinder.FIRST_CALL_TRANSACTION+ 3);

}

publicjava.lang.String EvDigitPress(intd)throwsandroid.os.RemoteException;

publicjava.lang.String EvCPress()throwsandroid.os.RemoteException;

publicjava.lang.String EvPlusPress()throwsandroid.os.RemoteException;

publicjava.lang.String EvAssignPress()throwsandroid.os.RemoteException;

}

這個calInterface.java檔案是由aidl.exe工具程式所產出的。

首先,calInterface介面繼承了Android提供的IInterface介面,如下述程式碼

publicinterfacecalInterfaceextendsandroid.os.IInterface

{

………

}

這個類別定義又內含有一個Stub類別,其繼承Android提供的Binder父類別,而且實作calInterface介面,如下述程式碼:

publicinterfacecalInterfaceextendsandroid.os.IInterface

{

……….

publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.misoo.gx06.calInterface

{

……….

privatestaticclassProxyimplementscom.misoo.gx06.calInterface

{

………

}

………..

}

由於Stub類別繼承了Binder父類別,而Binder又實作了IBinder介面,所以Stub類別支持兩個介面:IBindercalInterface。其內含的Proxy類別也支持calInterface

1-7IBindercalInterface介面之關係

1.4.4細說CalBinder類別的程式碼

基於這個結構,就可以從Stub類別衍生(Derive)出子類別:calBinder,其程式碼為:

/*---- CalBinder.java ----*/

packagecom.misoo.gx06;

importandroid.os.RemoteException;

publicclassCalBinderextendscalInterface.Stub{

privateCalculator mCal =null;

publicCalBinder(){

mCal =newCalculator();

}

@Override

publicString EvAssignPress()throwsRemoteException {

mCal.EvAssignPress();

returnmCal.retStr;

}

@Override

publicString EvCPress()throwsRemoteException {

mCal.EvCPress();

returnmCal.retStr;

}

@Override

publicString EvDigitPress(intd)throwsRemoteException {

mCal.EvDigitPress(d);

returnmCal.retStr;

}

@Override

publicString EvPlusPress()throwsRemoteException {

mCal.EvPlusPress();

returnmCal.retStr;

}

}

其中,指令:

publicCalBinder(){

mCal =newCalculator();

}

誕生了一個Calculator物件,如此與Calculator類別銜接起來了。

1.4.5函數呼叫的情境

此範例程式需要用到AIDL類別的詳細函數如下圖所示:

1-8AIDL各類別裡的函數及其關係

只要對物件觀念和技術較為熟悉的話,就可看出來其並不太複雜,只是基本物件觀念之應用而已。更詳細之說明,請看高煥堂所寫的第2Android書:<<Android軟體架構設計>>一書。

更多相关文章

  1. Android高手进阶教程(十九)---Android中几种图像特效处理的集锦!
  2. android 中 padding与margin的区别
  3. Android高手进阶教程(二十二)之---Android中几种图像特效处理的
  4. 深刻解析 Android(安卓)的 AIDL
  5. Google Android操作系统内核编译图文教程
  6. Android(安卓)资源(resource)学习小结
  7. Google Android操作系统内核编译图文教程
  8. Google Android操作系统内核编译图文教程
  9. Android和设计模式:享元模式

随机推荐

  1. Android提高第十八篇之自定义PopupWindow
  2. android介绍以及学习方法
  3. Android am 指令的使用
  4. android获取设备唯一标识完美解决方案
  5. C#/mono开发Android应用程序入门(二)-第一
  6. 详细的北京安卓培训班课程内容介绍
  7. Android的消息机制————读书笔记
  8. Only the original thread that created
  9. Android控件开发——ListView
  10. android使用属性动画代替补间动画