java類sample是公共的_應在名samle.java的文件_Andoid NDK編程 1 - 注冊native函數

打算對Android的NDK的開發做一總結,首先是JNI部分,接下來是NDK的內容。今天首先介紹一下JNI的第一部分:注冊native函數。

當java代碼中執行native的代碼時候,首先是通過一定的方法來找到這些native方法。而注冊native函數的具體方法的不同,會導致系統在運行時采用不同的方式來尋找這些native方法。

JNI有如下兩種注冊native方法的途徑:靜態和動態。其中:

靜態:先由Java得到本地方法的聲明,然后再通過JNI實現該聲明方法。

動態:先通過JNI重載JNI_OnLoad()實現本地方法,然后直接在Java中調用本地方法。

靜態注冊

根據函數名找到對應的JNI函數:Java層調用函數時,會從對應的JNI中尋找該函數,如果沒有就會報錯,如果存在則會建立一個關聯聯系,以后在調用時會直接使用這個函數,這部分的操作由虛擬機完成。

靜態方法就是根據函數名來遍歷java和jni函數之間的關聯,而且要求jni層函數的名字必須遵循

特定的格式。

具體的實現很簡單,首先在java代碼中聲明native函數,然后通過javah來生成native函數的具體形式,接下來在JNI代碼中實現這些函數即可。

看個例子就更明了了:

Java層:

static {

System.loadLibrary("samplelib_jni");

registerNatives();

}

private native void nativeFunc1();

private native void nativeFunc2();

private native void nativeFunc3();

接下來通過javah來產生jni代碼聲明:

假設你的java文件的包名是com.jni.samle 而類名是JniSample。

javah -d ./jni/ -classpath /Users/YOUR_NAME/Library/Android/sdk/platforms/android-21/android.jar:../../build/intermediates/classes/debug/ com.jni.samle.JniSample

然后就會得到一個JNI的.h文件,里面包含這幾個native函數的聲明,觀察一下文件名以及函數名,會有一定的規律,我會在下一篇文章中對此做一詳細介紹,在此不再贅述。

最后實現jni層的native方法即可。

動態注冊

對Java程序員來說,可能我們總是會遵循:1.編寫帶有native方法的Java類;—->2.使用javah命令生成.h頭文件;—->3.編寫代碼實現頭文件中的方法,這樣的標準流程,但也許有人無法忍受那“丑陋”的方法名稱,所以我們可以采用動態注冊方法,也就是通過RegisterNatives方法把c/c++中的方法隱射到Java中的native方法,而無需遵循特定的方法命名格式。

JNI 允許你提供一個函數映射表,注冊給Jave虛擬機,這樣Jvm就可以用函數映射表來調用相應的函數,

就可以不必通過函數名來查找需要調用的函數了。

Java與JNI通過JNINativeMethod的結構來建立聯系,它在jni.h中被定義,其結構內容如下:

typedef struct {

const char* name;

const char* signature;

void* fnPtr;

} JNINativeMethod;

第一個變量name是Java中函數的名字。

第二個變量signature,用字符串是描述了函數的參數和返回值

第三個變量fnPtr是函數指針,指向C函數。

當java通過System.loadLibrary加載完JNI動態庫后,緊接著會查找一個JNI_OnLoad的函數,如果有,就調用它, 而動態注冊的工作就是在這里完成的。

一起來看一下具體的實現方法:

Java code:

比較簡單,僅僅是加載so庫。

static {

System.loadLibrary("samplelib_jni");

}

JNI code:

在JNI中實現

jint JNI_OnLoad(JavaVM* vm, void* reserved)

并且在這個函數里面去動態的注冊native方法,完整的參考代碼如下:

#include

#include "Log4Android.h"

#include

#include

using namespace std;

#ifdef __cplusplus

extern "C" {

#endif

static const char *className = "com/zhixin/jnisample/JniManager";

static void sayHello(JNIEnv *env, jobject, jlong handle) {

LOGI("JNI", "native: say hello ###");

}

static JNINativeMethod gJni_Methods_table[] = {

{"sayHello", "(J)V", (void*)sayHello},

};

static int jniRegisterNativeMethods(JNIEnv* env, const char* className,

const JNINativeMethod* gMethods, int numMethods)

{

jclass clazz;

LOGI("JNI","Registering %s natives\n", className);

clazz = (env)->FindClass( className);

if (clazz == NULL) {

LOGE("JNI","Native registration unable to find class '%s'\n", className);

return -1;

}

int result = 0;

if ((env)->RegisterNatives(clazz, gJni_Methods_table, numMethods) < 0) {

LOGE("JNI","RegisterNatives failed for '%s'\n", className);

result = -1;

}

(env)->DeleteLocalRef(clazz);

return result;

}

jint JNI_OnLoad(JavaVM* vm, void* reserved){

LOGI("JNI", "enter jni_onload");

JNIEnv* env = NULL;

jint result = -1;

if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

return result;

}

jniRegisterNativeMethods(env, className, gJni_Methods_table, sizeof(gJni_Methods_table) / sizeof(JNINativeMethod));

return JNI_VERSION_1_4;

}

#ifdef __cplusplus

}

#endif

比較

下面我們來比較一下這兩種不同的實現方法。

首先是靜態方法:

優點實現起來比較簡單,直接用javah就能將Java代碼中的native函數的聲明轉化為native代碼的函數。

缺點在于:javah生成的jni層函數特別長;

初次調用native函數時要根據名字搜索對應的jni層函數來建立關聯聯系,這樣影響效率。

而動態方法的優缺點剛好和靜態方法相反。

通過上面的介紹我們發現,盡管靜態注冊實現起來比較簡單,但是會導致效率相對來說比較低。

所以在JNI層提供JNI_OnLoad是一個推薦的做法。如果不提供JNI_OnLoad,那么JNI函數的命名就需要符合規范,并且需要導出該函數。這樣做很容易被別人反編譯。相反,如果提供JNI_OnLoad,就可以在里面自己注冊JNI函數給Dalvik VM,這樣JNI函數的命名就可以按照自己的習慣了,而且也不用導出。

一個巧妙的合作

在實際的應用中,我們可以巧妙的將靜態注冊和動態注冊結合起來:也就是在java代碼中仍然聲明一個native函數,但是這個函數僅僅是用來去觸發在JNI層的native函數的動態注冊。說的有些繞,看看代碼就明白了:

Java層:

static {

System.loadLibrary("samplelib_jni");

registerNatives();

}

private static native void registerNatives();

JNI層:

通過javah生成java層聲明的native函數的文件,并且在實現代碼中去動態注冊JNI函數:

JNIEXPORT void JNICALL Java_com_zhixin_jni_JniSample_registerNatives

(JNIEnv *env, jclass clazz){

(env)->RegisterNatives(clazz, gJni_Methods_table, sizeof(gJni_Methods_table) / sizeof(JNINativeMethod));

}

后續

關于JNI的函數注冊就到這里了,在下一篇文章中會總結JNI的簽名規則問題。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/283011.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/283011.shtml
英文地址,請注明出處:http://en.pswp.cn/news/283011.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

WPF Canvas 平滑筆跡

WPF Canvas 平滑筆跡控件名&#xff1a;CanvasHandWriting作者&#xff1a;小封&#xff08;鄺攀升&#xff09;原文鏈接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers編輯&#xff1a;驚鏵完整的思路如下收集路徑點集。平均采樣路徑點集。將路徑點集轉為…

IIS應用程序池相關問題及連接池已滿的解決方法

關于應用程序池 在 IIS 6.0 中,引入了應用程序池&#xff0c;應用程序池是將一個或多個應用程序鏈接到一個或多個工作進程集合的配置。因為應用程序池中的應用程序與其他應用程序被工作進程邊界分隔&#xff0c;所以某個應用程序池中的應用程序不會受到其他應用程序池中應用程序…

echo -n 和echo -e 參數意義

echo -n 不換行輸出 $echo -n "123" $echo "456" 12最終輸出 123456而不是 123 456 123456echo -e 處理特殊字符 若字符串中出現以下字符&#xff0c;則特別加以處理&#xff0c;而不會將它當成一般文字輸出&#xff1a; \a 發出警告聲&#xff1b; \b 刪…

NetSpeed

NetSpeed公司提供的NOC包括三部分&#xff0c;可以通過NocStudio進行配置生成。 1)NetSpeed Orion&#xff0c;面向快速SoC design的可綜合平臺。 2)Linley NetSpeed NoC面向復雜的interconnect實現&#xff0c;同時優化內部physical implementation和timing closure. NoC是基于…

js ajax java傳參_ajax參數傳遞與后臺接收

ajax參數傳遞與后臺接收Servlet中讀取http參數的方法Enumeration getParameterNames() 返回一個 String 對象的枚舉&#xff0c;包含在該請求中包含的參數的名稱String getParameter(String name) 以字符串形式返回請求參數的值&#xff0c;或者如果參數不存在則返回 null。Str…

init 訪問器只能初始化時賦值,是真的嗎?

前言C# 提供的 init 關鍵字用于在屬性中定義訪問器方法&#xff0c;可以讓屬性僅能在對象初始化的時候被賦值&#xff0c;其他時候只能為只讀屬性的形式。例如下面代碼可以正常執行&#xff1a;public class Demo {public string Name { get; init; } }var demo new Demo { Na…

eclipse實現代碼塊折疊-類似于VS中的#region……#endregion

背 景 剛才在寫代碼的時候&#xff0c;寫了十幾行可以說是重復的代碼&#xff1a; 如果整個方法或類中代碼多了&#xff0c;感覺它們太TM占地方了&#xff0c;給讀者在閱讀代碼上造成很大的困難&#xff0c;于是想到能不能把他們“濃縮”成一行&#xff0c;腦子里第一個閃現出的…

添加Chrome插件(Github上下載的壓縮文件)

首先把壓縮包解壓到某個文件夾 然后按照以下步驟進行即可&#xff1a; 點擊Chrome瀏覽器上的設置->擴展程序->開發者模式->點擊加載已解壓的壓縮文件->選中解壓過的文件夾確定即可。轉載于:https://www.cnblogs.com/yijianzhongqing/p/6277838.html

java定義基礎變量語句_java語言基礎-變量

一丶變量的基本概念1.什么是變量(1).內存中的一個存儲區域(2).該區域有自己的名稱(變量名),和類型(數據類型)(3.)該區域的數據可以在同一類型范圍內不斷變化(定義變量的主要目的是因為數據的不確定性)2.為什么要定義變量用來不斷存放同一類型的常量&#xff0c;并可以重復使用3…

C# WPF MVVM模式[經典]案例

01—前言Caliburn.Micro(簡稱CM)一經推出便備受推崇&#xff0c;作為一款MVVM開發模式的經典框架&#xff0c;越來越多的受到wpf開發者的青睞.我們看一下官方的描述&#xff1a;Caliburn是一個為Xaml平臺設計的小型但功能強大的框架。Micro實現了各種UI模式&#xff0c;用于解決…

shell數組

定義數組[rootwy shell]# a(1 2 3 4)顯示數組[rootwy shell]# echo ${a[]}1 2 3 4[rootwy shell]# echo ${a[*]}1 2 3 4顯示數組中的某個元素[rootwy shell]# echo ${a[0]}1增加元素[rootwy shell]# a[4]9[rootwy shell]# echo ${a[*]}1 2 3 4 9修改元素值 [rootwy shell]# a[2…

java二級程序題兩個角度_兩個角度圖_【SCME大一】使用JAVA語言深入理解程序邏輯答案_學小易找答案...

【填空題】《蝶戀花 佇倚危樓風細細 》的作者( )。【簡答題】簡要概述問卷調查的整體設計?【填空題】父母在,( ),游必有方。【填空題】白居易與劉禹錫并稱“( )”。【填空題】白居易,字( )。【填空題】白居易,是唐代偉大的( )主義詩人。【單選題】《紅樓夢》最成功處在于塑造了…

LINUX中常用操作命令

LINUX中常用操作命令 引用&#xff1a;http://www.daniubiji.cn/archives/25 Linux簡介及Ubuntu安裝 常見指令系統管理命令打包壓縮相關命令關機/重啟機器Linux管道Linux軟件包管理vim使用用戶及用戶組管理文件權限管理Linux簡介及Ubuntu安裝 Linux&#xff0c;免費開源&#x…

Log4j編寫

來自: http://www.blogjava.net/zJun/archive/2006/06/28/55511.html Log4J的配置文件(Configuration File)就是用來設置記錄器的級別、存放器和布局的&#xff0c;它可接keyvalue格式的設置或xml格式的設置信息。通過配置&#xff0c;可以創建出Log4J的運行環境。1. 配置文件L…

C# 為什么高手喜歡用StartsWith而不是Substring進行字符串匹配?

字符串的截取匹配操作在開發中非常常見&#xff0c;比如下面這個示例&#xff1a;我要匹配查找出來字符串數組中以“abc”開頭的字符串并打印&#xff0c;我下面分別用了兩種方式實現&#xff0c;代碼如下&#xff1a;using System;namespace ConsoleApp23 {class Program{stat…

Nginx 服務器開啟status頁面檢測服務狀態

原文&#xff1a;http://www.cnblogs.com/hanyifeng/p/5830013.html 一、Nginx status monitor 和apache 中服務器狀態一樣。輸出的內容如&#xff1a; 第1列&#xff1a; 當前與http建立的連接數&#xff0c;包括等待的客戶端連接&#xff1a;2第2列&#xff1a;接受的客戶端連…

elif是不是java關鍵字_C# 中的#if、#elif、#else、#endif等條件編譯符號 (轉載)

這些是C#中的條件編譯符號。這些指令我在項目中遇到過&#xff0c;查過網絡&#xff0c;問過人(當然&#xff0c;既不認識大牛&#xff0c;也不認識小牛&#xff0c;所以沒什么收獲)。今天翻看一本資料&#xff0c;有提到這個方面的東西&#xff0c;所以寫下來和能看到這篇文章…

從零開始React項目架構(四)

前言 使用當前的webpack配置能不能打包構建項目呢&#xff1f;當然可以&#xff0c;但這不是我們想要的&#xff0c;所以&#xff0c;讓我們來看一看生產環境需要怎么配置webpack吧 開發 生產環境配置 在根目錄創建webpack.pro.config.jsconst path require(path) const webpa…

在OpenCloudOS 上安裝.NET 6

開源操作系統社區 OpenCloudOS 由騰訊與合作伙伴共同倡議發起&#xff0c;是完全中立、全面開放、安全穩定、高性能的操作系統及生態。OpenCloudOS 沉淀了多家廠商在軟件和開源生態的優勢&#xff0c;繼承了騰訊在操作系統和內核層面超過10年的技術積累&#xff0c;在云原生、穩…

Linux 命令詳解(二)awk 命令

AWK是一種處理文本文件的語言&#xff0c;是一個強大的文本分析工具。之所以叫AWK是因為其取了三位創始人 Alfred Aho&#xff0c;Peter Weinberger, 和 Brian Kernighan 的Family Name的首字符。 語法&#xff1a; awk [選項參數] script varvalue file(s) 或 awk [選項參數] …