成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Android架構師之路:JNI與NDK編程-函數注冊與C++調用Java詳解(c++音視頻編碼基礎)

開發 前端
這篇文章講解jni中函數的注冊和c++調用java的知識點;JNI技術是Java世界與Native世界的通信橋梁,具體到代碼,Java層的代碼如何同Native層的代碼進行調用的呢?

[[412937]]

前言小計

1、jni與ndk的基本知識點前面文章都講過了,不懂的,可以在公眾號首頁看;

2、jni中常用的方法比如:類、方法、數組、字符串等前面也講解過了;

3、這篇文章講解jni中函數的注冊和c++調用java的知識點;

一. JNI函數注冊

圖片

1、jni函數注解知識點介紹

  • JNI技術是Java世界與Native世界的通信橋梁,具體到代碼,Java層的代碼如何同Native層的代碼進行調用的呢?我們都知道,在調用native方法之前,首先要調用System.loadLibrary接口加載一個實現了native方法的動態庫才能正常訪問,否則就會拋出java.lang.UnsatisfiedLinkError異常 。那么,在Java中調用某個native方法時,JVM是通過什么方式,能正確的找到動態庫中C/C++實現的那個native函數呢?
  • JVM查找native方法有兩種方式;
  • 按照JNI規范的命名規則,調用JNI提供的RegisterNatives函數,將本地函數注冊到JVM中;
  • 第一種方式,可用使用javah工具按照Java類中定義的native方法,按照JNI規范的命名規則的方式自動生成Jni本地C/C++頭文件;
  • 第二種方式則需要在本地庫的JNI_OnLoad函數中調用RegisterNatives來動態注冊;
  • JNI函數注冊是將Java層聲明的Native方法同實際的Native函數綁定起來的實現方式,也就是說,只要通過JNI函數注冊機制注冊了本地方,Java層就可以直接調用定義的這些本地方法了。對應上述JVM查找native方法的兩種方式,JNI函數注冊方式一般分為靜態注冊和動態注冊兩種方式。

2、靜態注冊

原理:根據函數名來建立 java 方法與 JNI 函數的一一對應關系;

實現流程:

  • 編寫 java 代碼;
  • 利用 javah 指令生成對應的 .h 文件;
  • 對 .h 中的聲明進行實現;

弊端:

編寫不方便,JNI 方法名字必須遵循規則且名字很長;

編寫過程步驟多,不方便;

程序運行效率低,因為初次調用native函數時需要根據根據函數名在JNI層中搜索對應的本地函數,然后建立對應關系,這個過程比較耗時;

  1. public class Test { 
  2.     static { 
  3.         System.loadLibrary("native-lib"); 
  4.     } 
  5.     public native String textFromJni(); 
  6. 使用javah生成對應的本地方法頭文件。 
  7. #include <jni.h> 
  8. #ifndef _Included_test 
  9. #define _Included_test 
  10. #ifdef __cplusplus 
  11. extern "C" { 
  12. #endif 
  13. JNIEXPORT jstring JNICALL Java_test_Test_textFromJni 
  14.   (JNIEnv *, jobject); 
  15. #ifdef __cplusplus 
  16. #endif 

3、動態注冊

對應與上面的靜態注冊方法,還有一種動態注冊JNI函數的方式,即動態注冊。動態注冊是當Java層調用System.loadLibrary方法加載so庫后,本地庫的JNI_OnLoad函數會被調用,在JNI_OnLoad函數中通過調用RegisterNatives函數來完成本地方法的注冊。

原理:利用 RegisterNatives 方法來注冊 java 方法與 JNI 函數的一一對應關系;

實現流程:

  • 利用結構體 JNINativeMethod 數組記錄 java 方法與 JNI 函數的對應關系;
  • 實現 JNI_OnLoad 方法,在加載動態庫后,執行動態注冊;
  • 調用 FindClass 方法,獲取 java 對象;
  • 調用 RegisterNatives 方法,傳入 java 對象,以及 JNINativeMethod 數組,以及注冊數目完成注冊;

優點:

流程更加清晰可控;

效率更高;

其中JNINativeMethod結構體用來描述本地方法結構,其定義如下:

  1. typedef struct { 
  2.     const charname;      // Java方法名 
  3.     const char* signature; // Java方法簽名 
  4.     void* fnPtr;           // jni本地方法對應的函數指針 
  5. } JNINativeMethod; 

結構體的第一個參數 name 是java 方法名;

第二個參數 signature 用于描述方法的參數與返回值;

第三個參數 fnPtr 是函數指針,指向 jni 函數;

其中,第二個參數 signature 使用字符串記錄方法的參數與返回值,具體格式形如“()V”、“(II)V”,其中分為兩部分,括號內表示的是參數,括號右側表示的是返回值;

①、數據類型映射

基本數據類型

②. 數組引用類型

如果是一維數組則遵循下表,如果是二維數組或更高維數組則對應的 native 類型為 jobjectArray,域描述符中使用 ‘[’ 的個數表示維數

③. 對象引用類型

對于其它引用類型,即 java 中的對象,其映射規則為

④. 對象數組引用類型

如果是一維數組則遵循下表,如果是二維數組或更高維數組則對應的 native 類型為 jobjectArray,域描述符中使用 ‘[’ 的個數表示維數

在Java文件中定義本地方法,加載本地so庫

  1. package test.jnitest; 
  2. public class Test { 
  3.     static { 
  4.         System.loadLibrary("native-lib"); 
  5.     } 
  6.     public native String textFromJni(); 

在JNI_OnLoad函數中注冊本地方法

  1. jstring textFromJni(JNIEnv* env, jobject thiz) { 
  2.     return env->NewStringUTF("text from jni"); 
  3. static JNINativeMethod gMethods[] = { 
  4.         {"textFromJni""()Ljava/lang/String;", (void*)textFromJni} 
  5. }; 
  6. int registerMethod(JNIEnv *env) { 
  7.     jclass test = env->FindClass("cc/ccbu/jnitest/Test"); 
  8.     return env->RegisterNatives(test, gMethods, sizeof(gMethods)/ sizeof(gMethods[0])); 
  9. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { 
  10.     JNIEnv* env = NULL
  11.     if (vm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) { 
  12.         return JNI_ERR; 
  13.     } 
  14.     if (registerMethod(env) != JNI_OK) { 
  15.         return JNI_ERR; 
  16.     } 
  17.     return  JNI_VERSION_1_6; 

注意:

在JNI_OnLoad函數的結尾處,我們一定要有返回值,而且必須是JNI_VERSION_1_4 或 JNI_VERSION_1_6,也就是JNI的版本號,我們一定要返回正確的版本號,否則系統也是無法加載的;

4、c++調用java詳解

(1) 找到java對應的Class

(2) 找到要調用的方法的methodID

(3) 在C語言中調用相應方法

①.通過JAVA層的本地方法創建同類對象

步驟:

I.通過對象獲取類

II.通過類獲取類的構造方法的ID

III.基于方法ID和類,創建新對象

  1. JNIEXPORT void JNICALL JAVA_nativeMethod 
  2.         (JNIEnv *env, jobject thiz,jint i){ 
  3.     ... 
  4.     jclass clazz = (*env).GetObjectClass(thiz); 
  5.     jmethodID mid = (*env).GetMethodID(clazz,"<init>","()V"); 
  6.     jobject obj = (*env).NewObject(clazz,mid); 
  7.     ... 
  8.     return

②.通過C/C++創建不同類對象

步驟:

I.通過FindClass方法獲取需要的類

II.通過類獲取類的構造方法的ID

III.基于方法ID和類,創建新對象

  1. JNIEXPORT void JNICALL JAVA_nativeMethod 
  2.         (JNIEnv *env, jobject thiz,jint i){ 
  3.     ... 
  4.     jclass clazz = (*env).FindClass("com/x/test/Test");//參數為類路徑 
  5.     jmethodID mid = (*env).GetMethodID(clazz,"<init>","()V"); 
  6.     jobject obj = (*env).NewObject(clazz,mid); 
  7.     ... 
  8.     return

③獲取上下文環境JNIEnv

如果找不到上下文JNIEnv就要獲取

  1. bool AttachCurrentThread(JavaVM* vm, JNIEnv** p_env) 
  2.     bool bAttached = false
  3.  
  4.     switch(vm->GetEnv((void**)p_env, JNI_VERSION_1_4)) 
  5.     { 
  6.         case JNI_OK: 
  7.             break; 
  8.         case JNI_EDETACHED: 
  9.  
  10.             if (vm->AttachCurrentThread(p_env, 0) < 0) 
  11.             { 
  12.                 LOGD("%s :test failed!",__func__); 
  13.                 return false
  14.             } 
  15.             else 
  16.             { 
  17.                 bAttached = true
  18.             } 
  19.             break; 
  20.         case JNI_EVERSION: 
  21.             LOGE("Invalid java version"); 
  22.             break; 
  23.     } 
  24.   return bAttached; 
  25.  

總結

以上總結了JNI中函數注冊的兩種方法,在實際應用中都很常見都用得到的,要理解到位才可以;

下次文章會繼續講解關于JNI的知識點和高級應用

本文轉載自微信公眾號「Android開發編程」,可以通過以下二維碼關注。轉載本文請聯系Android開發編程公眾號。

 

責任編輯:姜華 來源: Android開發編程
相關推薦

2021-07-20 05:34:45

JNINDKC++

2011-07-01 14:55:28

Qt QML C++

2009-07-20 09:53:43

Java混合編程

2012-04-28 15:28:21

JNI混合編程Java

2010-01-28 13:35:41

調用C++函數

2010-01-19 15:36:02

C++語言

2011-08-04 13:38:01

Objective-C C++

2025-04-02 03:11:00

Python函數C++

2012-03-20 11:37:24

JavaJNI

2010-02-01 16:13:15

C++繼承

2010-01-11 10:28:51

C++編程

2011-08-22 17:13:00

LuaC++函數

2010-01-21 11:23:58

C++函數調用

2010-01-25 09:57:39

C++函數參數

2010-01-12 17:55:03

C++程序

2010-02-02 15:59:32

C++賦值函數

2009-08-13 17:30:30

C#構造函數

2011-07-14 17:45:06

CC++

2011-07-15 00:47:13

C++多態

2011-07-10 15:26:54

C++
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品一区二区久久久久久久网站 | 日韩和的一区二在线 | 99国内精品| 岛国毛片在线观看 | 国产福利在线 | 一级视频黄色 | 国产成人免费视频网站高清观看视频 | 日韩综合色| 羞羞网站在线观看 | 国产亚洲精品综合一区 | 爱爱爱av | 久久专区 | 网站黄色在线免费观看 | 国产91一区 | 特级黄一级播放 | 国产激情一区二区三区 | 国产美女在线观看 | 日韩欧美在线免费观看 | 99久久精品免费看国产高清 | 毛片黄片免费看 | av在线影院 | 免费在线观看一区二区三区 | 亚洲成人一区 | 欧美一区免费 | 成人高清视频在线观看 | h片在线播放 | 免费a大片 | 久久国产欧美日韩精品 | 色婷婷精品 | 精品九九九| 999久久久精品 | 国产伦精品一区二区三区在线 | 伊人狠狠干 | 亚洲成人免费视频在线观看 | 在线伊人网 | 国产精品美女久久久久aⅴ国产馆 | 国产精品久久久久久久粉嫩 | 国精品一区二区 | 国产亚洲精品美女久久久久久久久久 | 午夜网 | 国产成人免费视频 |