NDK 与 JNI 的关系
簡介
?JNI是java語言提供的Java和C/C++相互溝通的機制,Java可以通過JNI調(diào)用本地的C/C++代碼,本地的C/C++的代碼也可以調(diào)用java代碼。JNI 是本地編程接口,Java和C/C++互相通過的接口。Java通過C/C++使用本地的代碼的一個關(guān)鍵性原因在于C/C++代碼的高效性。
NDK是一系列工具的集合。它提供了一系列的工具,幫助開發(fā)者快速開發(fā)C(或C++)的動態(tài)庫,并能自動將so和java應(yīng)用一起打包成apk。這些工具對開發(fā)者的幫助是巨大的。它集成了交叉編譯器,并提供了相應(yīng)的mk文件隔離CPU、平臺、ABI等差異,開發(fā)人員只需要簡單修改mk文件(指出“哪些文件需要編譯”、“編譯特性要求”等),就可以創(chuàng)建出so。它可以自動地將so和Java應(yīng)用一起打包,極大地減輕了開發(fā)人員的打包工作。
Java通過JNI機制和C/C++溝通的具體步驟
1、編寫包含native本地方法的java類
2、通過javah工具生成C/C++語言的頭文件
3、使用C/C++語言實現(xiàn)頭文件
4、使用交叉編譯工具對C/C++本地代碼進(jìn)行編譯,最后通過鏈接生成*.so可執(zhí)行的C/C++庫
5、實際執(zhí)行Java代碼去和本地的C/C++代碼互相溝通
JNI中的JavaVM與JNIEnv對象
在標(biāo)準(zhǔn)的Java平臺下,每個Process里可以產(chǎn)生很多JavaVM對象,每個JavaVM對象都有一個與之對應(yīng)的JavaVM對象,但是在Android平臺上,每個Process只能產(chǎn)生一個DalvikVM對象,也就是說在一個Android的進(jìn)程中是通過有且只有一個虛擬器對象來服務(wù)所有Java和C++代碼的。
1、JNIEnv *內(nèi)部包含一個Pointer,Pointer指向Dalvik的JavaVM對象的Fanction Table,JNIEnv *關(guān)于程序執(zhí)行環(huán)境的眾多函數(shù)正是來源于Dalvik虛擬機
2、Android中每當(dāng)一個Java線程第一次要調(diào)用本地C/C++代碼時,Dalvik虛擬機實例會為該Java線程產(chǎn)生一個JNIEnv *指針
3、Java每條線程在和C/C++互相調(diào)用時,JNIEnv*是相互獨立的,互不干擾
4、每本地的C/C++代碼想獲得當(dāng)前線程所要使用的JNIEnv時,可以使用Dalvik VM對象的Java VM* jvm->getEnv()方法,該方法即會返回當(dāng)前線程所在的JNIEnv*
Java、Dalvik VM、C/C++的運行機制與流程
在Android的NDK中,Java、C/C++、Dalvik VM關(guān)系如下:
1、java的dex字節(jié)碼和C/C++的*.so同時運行DalvikVM之內(nèi),共同使用一個進(jìn)程空間。每次使用jni調(diào)用c/c++開辟一個線程去處理
2、java和C/C++可以相互調(diào)用,調(diào)用的關(guān)鍵是DalvikVM
3、一般而言,比較經(jīng)典的模式是Java通過JNI的C組建和C++相互溝通,一般業(yè)務(wù)處理放在C/C++中
4、C++代碼處于核心控制地位更具價值
當(dāng)java需要C/C++代碼時,在DalvikVM虛擬機中加載動態(tài)鏈接庫時,會先調(diào)用JNI_Onload()函數(shù),此時就會把javaVM對象的指針存儲于C層JNI組建的全局環(huán)境中,在JAVA層調(diào)用C層的本地庫函數(shù)時,調(diào)用C本地函數(shù)線程必然通過Dalvik VM來調(diào)用C本地函數(shù),測試Dalvik虛擬機會為本地的C組建實例化一個JNIEnv指針,該指針指向Dalvik虛擬機的具體函數(shù)列表,當(dāng)JNI的C組件調(diào)用java層方法和屬性時,需要通過JNIEnv指針來進(jìn)行調(diào)用。
當(dāng)C++組件主動調(diào)用Java層方法時,需要通過JNI的C組件把JNIEnv指針傳遞給C++組件,此后,c++組件即可通過JNIEnv指針來掌控Java層代碼。
總結(jié)
對于JNI和NDK很多Android開發(fā)初學(xué)者沒有搞明白這個問題,JNI是Java調(diào)用Native機制,是Java語言自己的特性全稱為Java Native Interface,類似的還有微軟.Net Framework上的p/invoke,可以讓C#或Visual Basic.Net可以調(diào)用C/C++的API,所以說JNI和Android沒有關(guān)系,在PC上開發(fā)Java的應(yīng)用,如果運行在Windows平臺使用JNI是是經(jīng)常的,比如說讀寫Windows的注冊表。而NDK是Google公司推出的幫助Android開發(fā)者通過C/C++本地語言編寫應(yīng)用的開發(fā)包,包含了C/C++的頭文件、庫文件、說明文檔和示例代碼,我們可以理解為Windows Platform SDK一樣,是純C/C++編寫的,但是Android并不支持純C/C++編寫的應(yīng)用,同時NDK提供的庫和函數(shù)功能很有限,僅僅處理些算法效率敏感的問題,所以Android123推薦初學(xué)者學(xué)好Java后再學(xué)習(xí)JNI。
簡單點說,用C語言生成一個庫文件,在java中調(diào)用這個庫文件的函數(shù)。JNI的過程比較復(fù)雜,生成.so需要大量操作,而NDK就是簡化了這個過程。
總結(jié)
以上是生活随笔為你收集整理的NDK 与 JNI 的关系的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android之NDK开发
- 下一篇: 用javah 导出类的头文件, 常见的错