我们都知道Android是基于Linux,但是它的上层开发又是以Java,那么他们之间是怎么相互调用的呢?

网上看了搜索了很久也没有找到相关的文章,下面转载一篇文章

 在Android應用框架裡,應用層級的軟體大多是Java類別,而系統層級的軟體大多是C或 C++類別。Android使用JNI介面來達成這個目標。例如,在Android裡有個MediaPlayer.cpp類別,當它搭配上JNI介面之 後,在VM上執行的MediaPlayer.java就可以透過JNI介面與MediaPlayer.cpp類別溝通了。

(JNI)

这里必须要有一个libmedia_jin.so来与下层沟通,这个so一定要按照某种标准来实现。

基於這樣的架構,我門就可以盡量將MediaPlayer.java裡的程式邏輯移入MediaPlayer.cpp類別裡,以便加快程式的執行速度。此 外,以JNI介面包裝MediaPlayer.cpp類別,並且銜接相互輝映的MediaPlayer.java類別,可以讓眾多的Java應用程式透過 MediaPlayer.java來使用MediaPlayer.cpp類別的服務。這是一種非常有用的包裝技巧,藉由包裝來創造更多的應用機會。

我们把时间要求很高的操作尽可能的放在cpp文件中,这样提高速度。

為了進一步創造更多的應用機會,可以替MediaPlayer.java類別加上AIDL介面,讓更多的Java應用程式能與MediaPlayer.java類別進行遠距的IPC溝通。如下圖所示:

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

於此,以高煥堂所寫的第2本Android書:<<Android 軟體架構設計>> 一書裡的範例:HalfAdder組件為例,展示其幕後的細節架構。首先看看其JNI介面之上的細節架構,如下UML圖:

上圖凸顯了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) throws android.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 軟體架構設計>> 一書。

更多相关文章

  1. Android(安卓)Studio1.5 配置Android(安卓)annotations
  2. 【方案汇总】在C/C++中使用Android(安卓)Log导致编译失败的问题
  3. android Jni 需要注意的地方
  4. Android第三课 联调华为手机
  5. Android中给listview/gridview设置动画(逐条加载条目动画)
  6. Android高手进阶教程(二十三)之---Android中的日历读写操作!!!
  7. Android高手进阶教程(四)之----Android(安卓)中自定义属性(attr.
  8. Android(安卓)C++层打印调用栈
  9. android 启动页面

随机推荐

  1. android DatePicker
  2. Android旋转动画不停顿
  3. Android Linux usb gadget configfs
  4. Android之qq盗号
  5. Android SDK r16 发布
  6. 一个不错的Android Market网站
  7. android SpannableString使用详解
  8. Android 热修复案例
  9. android 图片背景使用这种方式很爽
  10. Android(安卓)ViewPager 几种开发案例的