当前位置:   article > 正文

android ndk开发

android ndk开发
JNI 开发流程主要分为以下 6 步:
编写声明了 native 方法的 Java 类
将 Java 源代码编译成 class 字节码文件
用 javah -jni 命令生成 .h 头文件(javah 是 jdk 自带的一个命令,-jni 参数表示将 class 中用native 声明
的函数生成 JNI 规则的函数)
用本地代码实现 .h头 文件中的函数
将本地代码编译成动态库(Windows:\*.dll,linux/unix:\*.so,mac os x:\*.jnilib)
拷贝动态库至 java.library.path 本地库搜索目录下,并运行 Java 程序
  1. MainActivity类
  2. static {
  3. System.loadLibrary("HelloWorld");//引入so包
  4. }
  5. public static native String sayHi();//调用c/c++
  6. //生成h头文件
  7. 1.先选中java目录,然后右击open in ,选 Terminal。也就是进入java目录输入命令
  8. javah -classpath . -jni com.example.myapplication.MainActivity
  9. //新建一个cpp文件 把头文件复制粘贴进来
  10. JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_sayHi
  11. (JNIEnv *env, jclass){
  12. return env->NewStringUTF("from c语言");
  13. };
  14. //生成动态库方式
  15. 1) cmake
  16. 2) ndk-build
  17. 下面我用得是cmake
  18. CMakeLists.txt
  19. cmake_minimum_required(VERSION 3.18.1)
  20. project("HelloWorld")
  21. add_library( # Sets the name of the library.
  22. HelloWorld
  23. SHARED
  24. native-lib.cpp)
  25. find_library( # Sets the name of the path variable.
  26. log-lib
  27. log)
  28. target_link_libraries( # Specifies the target library.
  29. HelloWorld
  30. ${log-lib})
  31. app.gradle
  32. defaultConfig {
  33. ...
  34. externalNativeBuild {
  35. cmake {
  36. cppFlags ''
  37. }
  38. }
  39. }
  40. externalNativeBuild {
  41. cmake {
  42. path file('src/main/cpp/CMakeLists.txt')
  43. version '3.18.1'
  44. }
  45. }

2.传参数给c/c++和返回

  1. MainActivity类
  2. public static native String sayHi(String name);
  3. /*
  4. * Class: com_example_myapplication_MainActivity
  5. * Method: sayHi
  6. * Signature: ()Ljava/lang/String;
  7. */
  8. JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_sayHi
  9. (JNIEnv *env, jclass jclass, jstring jstring){
  10. //定义变量
  11. const char *c_str=NULL;
  12. char buff[128] ={0};
  13. //jstring转char
  14. c_str = (*env).GetStringUTFChars(jstring, NULL);
  15. if (c_str == NULL)
  16. {
  17. return NULL;
  18. }
  19. //释放jstring指向Char的指针
  20. (*env).ReleaseStringUTFChars(jstring, c_str);
  21. //发送格式化输出到buff所指向的字符串(c_str)
  22. sprintf(buff, "hello %s", c_str);
  23. return (*env).NewStringUTF(buff);
  24. }

3.数据类型对应(注意类型之间的对应)

  1. MainActivity类
  2. public static native void myTest(short s, int i, long l, float f, double d, char c,
  3. boolean z, byte b, String str, Object obj, Student p, int[] arr);
  4. C文件
  5. JNIEXPORT void JNICALL Java_com_example_myapplication_MainActivity_myTest
  6. (JNIEnv *env, jclass cls, jshort s, jint i, jlong l, jfloat f,
  7. jdouble d, jchar c, jboolean z, jbyte b, jstring j_str, jobject jobj1, jobject job2, jintArray j_int_arr)
  8. {
  9. printf("s=%hd, i=%d, l=%ld, f=%f, d=%lf, c=%c, z=%c, b=%d", s, i, l, f, d, c, z, b);
  10. const char *c_str = NULL;
  11. c_str = (*env).GetStringUTFChars(j_str,NULL);
  12. if (c_str == NULL)
  13. {
  14. return; // memory out
  15. }
  16. (*env).ReleaseStringUTFChars(j_str, c_str);
  17. printf("c_str: %s\n", (char*)c_str);
  18. }
  19. #ifdef __cplusplus

1.返回字符串

  1. public class MainActivity extends AppCompatActivity {
  2. static {
  3. System.loadLibrary("HelloWorld");
  4. }
  5. public static native String sayHi(String name);
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_main);
  10. TextView textView=findViewById(R.id.tv_hi);
  11. textView.setText(sayHi("gu"));
  12. }
  13. }
  14. /* DO NOT EDIT THIS FILE - it is machine generated */
  15. #include <jni.h>
  16. #include <cstdio>
  17. /* Header for class com_example_myapplication_MainActivity */
  18. #ifndef _Included_com_example_myapplication_MainActivity
  19. #define _Included_com_example_myapplication_MainActivity
  20. #ifdef __cplusplus
  21. extern "C" {
  22. #endif
  23. /*
  24. * Class: com_example_myapplication_MainActivity
  25. * Method: sayHi
  26. * Signature: ()Ljava/lang/String;
  27. */
  28. JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_sayHi
  29. (JNIEnv *env, jclass jclass, jstring jstring){
  30. //定义变量
  31. const char *c_str=NULL;
  32. char buff[128] ={0};
  33. //jstring拷贝
  34. c_str = (*env).GetStringUTFChars(jstring, NULL);
  35. if (c_str == NULL)
  36. {
  37. return NULL;
  38. }
  39. //发送格式化输出到buff所指向的字符串(c_str)
  40. sprintf(buff, "hello %s", c_str);
  41. //释放jstring指向Char的指针
  42. (*env).ReleaseStringUTFChars(jstring, c_str);
  43. return (*env).NewStringUTF(buff);
  44. }
  45. #ifdef __cplusplus
  46. }
  47. #endif
  48. #endif
  49. 错误用法:
  50. JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_sayHi
  51. (JNIEnv *env, jclass jclass, jstring jstring){
  52. //定义变量
  53. const jchar *c_str = NULL;
  54. char buff[128] = "hello";
  55. char *pBuff = buff + 6;
  56. /*
  57. * 在GetStringCritical/RealeaseStringCritical之间是一个关键区。
  58. * 在这关键区之中,绝对不能呼叫JNI的其他函数和会造成当前线程中断或是会让当前线程等待的任何本地代码,
  59. * 否则将造成关键区代码执行区间垃圾回收器停止运作,任何触发垃圾回收器的线程也会暂停。
  60. * 其他触发垃圾回收器的线程不能前进直到当前线程结束而激活垃圾回收器。
  61. */
  62. c_str=(*env).GetStringCritical(jstring,NULL); 返回源字符串指针的可能性
  63. if (c_str ==NULL){
  64. return NULL;
  65. }
  66. while (*c_str)
  67. {
  68. *pBuff++=*c_str++;
  69. }
  70. (*env).ReleaseStringCritical(jstring,c_str);
  71. return (*env).NewStringUTF(buff);
  72. }
  73. #define _Included_com_example_myapplication_MainActivity
  74. #ifdef __cplusplus
  75. extern "C" {
  76. #endif
  77. /*
  78. * Class: com_example_myapplication_MainActivity
  79. * Method: sayHi
  80. * Signature: ()Ljava/lang/String;
  81. */
  82. JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_sayHi
  83. (JNIEnv *env, jclass jclass, jstring jstring){
  84. jsize len=(*env).GetStringLength(jstring);
  85. char buff[128]="hello ";
  86. char* pBuff=buff+6;
  87. // 将JVM中的字符串以utf-8编码拷入C缓冲区,该函数内部不会分配内存空间
  88. (*env).GetStringUTFRegion(jstring, 0, len, pBuff);
  89. return (*env).NewStringUTF(buff);
  90. }
  91. #ifdef __cplusplus
  92. }
  93. #endif
  94. #endif

2.返回数组

  1. public class MainActivity extends AppCompatActivity {
  2. static {
  3. System.loadLibrary("HelloWorld");
  4. }
  5. private native int sumArray(int[] arr);
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_main);
  10. TextView textView = findViewById(R.id.tv_hi);
  11. int[] arr = new int[10];
  12. for (int i = 0; i < arr.length; i++) {
  13. arr[i] = i;
  14. }
  15. int sum = sumArray(arr);
  16. textView.setText("返回=="+sum);
  17. }
  18. }
  19. 第一种
  20. /* DO NOT EDIT THIS FILE - it is machine generated */
  21. #include <jni.h>
  22. #include <cstdio>
  23. #include <cstdlib>
  24. #include <cstring>
  25. /* Header for class com_example_myapplication_MainActivity */
  26. #ifndef _Included_com_example_myapplication_MainActivity
  27. #define _Included_com_example_myapplication_MainActivity
  28. #ifdef __cplusplus
  29. extern "C" {
  30. #endif
  31. /*
  32. * Class: com_example_myapplication_MainActivity
  33. * Method: sayHi
  34. * Signature: ()Ljava/lang/String;
  35. */
  36. JNIEXPORT jint JNICALL Java_com_example_myapplication_MainActivity_sumArray
  37. (JNIEnv *env, jobject obj, jintArray j_array){
  38. jint i, sum = 0;
  39. jint *c_array;
  40. jint arr_len;
  41. // 可能数组中的元素在内存中是不连续的,JVM可能会复制所有原始数据到缓冲区,然后返回这个缓冲区的指针
  42. c_array = (*env).GetIntArrayElements(j_array,NULL);
  43. if (c_array == NULL) {
  44. return 0; // JVM复制原始数据到缓冲区失败
  45. }
  46. arr_len = (*env).GetArrayLength(j_array);
  47. printf("arr_len = %d\n", arr_len);
  48. for (i = 0; i < arr_len; i++) {
  49. sum += c_array[i];
  50. }
  51. (*env).ReleaseIntArrayElements(j_array, c_array, 0); // 释放可能复制的缓冲区
  52. return sum;
  53. }
  54. #ifdef __cplusplus
  55. }
  56. #endif
  57. #endif
  58. 第二种
  59. /* DO NOT EDIT THIS FILE - it is machine generated */
  60. #include <jni.h>
  61. #include <cstdio>
  62. #include <cstdlib>
  63. #include <cstring>
  64. /* Header for class com_example_myapplication_MainActivity */
  65. #ifndef _Included_com_example_myapplication_MainActivity
  66. #define _Included_com_example_myapplication_MainActivity
  67. #ifdef __cplusplus
  68. extern "C" {
  69. #endif
  70. /*
  71. * Class: com_example_myapplication_MainActivity
  72. * Method: sayHi
  73. * Signature: ()Ljava/lang/String;
  74. */
  75. JNIEXPORT jint JNICALL Java_com_example_myapplication_MainActivity_sumArray
  76. (JNIEnv *env, jobject obj, jintArray j_array){
  77. jint i,sum=0;
  78. jint *c_array;
  79. jint arr_len;
  80. //1. 获取数组长度
  81. arr_len=(*env).GetArrayLength(j_array);
  82. //2. 根据数组长度和数组元素的数据类型申请存放java数组元素的缓冲区
  83. c_array= (jint*)malloc(sizeof(jint)*arr_len);
  84. //3. 初始化缓冲区
  85. memset(c_array,0,sizeof(jint)*arr_len);
  86. //4. 拷贝Java数组中的所有元素到缓冲区中
  87. (*env).GetIntArrayRegion(j_array,0,arr_len,c_array);
  88. for ( i = 0; i <arr_len ; ++i) {
  89. sum+=c_array[i];//5. 累加数组元素的和
  90. }
  91. free(c_array); //6. 释放存储数组元素的缓冲区
  92. return sum;
  93. }
  94. #ifdef __cplusplus
  95. }
  96. #endif
  97. #endif

二维数组

  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. #include <cstdio>
  4. #include <cstdlib>
  5. #include <cstring>
  6. /* Header for class com_example_myapplication_MainActivity */
  7. #ifndef _Included_com_example_myapplication_MainActivity
  8. #define _Included_com_example_myapplication_MainActivity
  9. #ifdef __cplusplus
  10. extern "C" {
  11. #endif
  12. /*
  13. * Class: com_example_myapplication_MainActivity
  14. * Method: sayHi
  15. * Signature: ()Ljava/lang/String;
  16. */
  17. JNIEXPORT jobjectArray JNICALL Java_com_example_myapplication_MainActivity_initInt2DArray
  18. (JNIEnv *env, jobject obj, jint size)
  19. {
  20. jobjectArray result;
  21. jclass clsIntArray;
  22. jint i,j;
  23. // 1.获得一个int型二维数组类的引用
  24. clsIntArray = (*env).FindClass("[I");
  25. if (clsIntArray == NULL)
  26. {
  27. return NULL;
  28. }
  29. // 2.创建一个数组对象(里面每个元素用clsIntArray表示)
  30. result = (*env).NewObjectArray(size,clsIntArray,NULL);
  31. if (result == NULL)
  32. {
  33. return NULL;
  34. }
  35. // 3.为数组元素赋值
  36. for (i = 0; i < size; ++i)
  37. {
  38. jint buff[256];
  39. jintArray intArr = (*env).NewIntArray(size);//创建一个 JNI 的 int 数组
  40. if (intArr == NULL)
  41. {
  42. return NULL;
  43. }
  44. for (j = 0; j < size; j++)
  45. {
  46. buff[j] = i + j;
  47. }
  48. //buff[]缓冲中的内容复制到新分配的一维数组中去
  49. (*env).SetIntArrayRegion(intArr, 0,size,buff);
  50. //在外层循环中依次将 int[]数组赋值到 jobjectArray 数组中
  51. (*env).SetObjectArrayElement(result, i, intArr);
  52. //DeleteLocalRef 将新创建的 jintArray 引用从引用表中移除
  53. (*env).DeleteLocalRef(intArr);
  54. }
  55. return result;
  56. }
  57. #ifdef __cplusplus
  58. }
  59. #endif
  60. #endif
  61. 下面是java
  62. public class MainActivity extends AppCompatActivity {
  63. static {
  64. System.loadLibrary("HelloWorld");
  65. }
  66. private native int[][] initInt2DArray(int size);
  67. @Override
  68. protected void onCreate(Bundle savedInstanceState) {
  69. super.onCreate(savedInstanceState);
  70. setContentView(R.layout.activity_main);
  71. TextView textView = findViewById(R.id.tv_hi);
  72. int[][] arr = initInt2DArray(3);
  73. for (int i = 0; i < 3; i++) {
  74. for (int j = 0; j < 3; j++) {
  75. System.out.format("arr[%d][%d] = %d\n", i, j, arr[i][j]);
  76. }
  77. }
  78. textView.setText("返回==");
  79. }
  80. }

CC++访问 Java 实例方法和静态方法

  1. public class MainActivity extends AppCompatActivity {
  2. static {
  3. System.loadLibrary("HelloWorld");
  4. }
  5. public static native void callJavaStaticMethod();
  6. public static native void callJavaInstaceMethod();
  7. @Override
  8. protected void onCreate(Bundle savedInstanceState) {
  9. super.onCreate(savedInstanceState);
  10. setContentView(R.layout.activity_main);
  11. callJavaStaticMethod();
  12. callJavaInstaceMethod();
  13. }
  14. }
  15. public class ClassMethod {
  16. private static void callStaticMethod(String str, int i) {
  17. System.out.format("ClassMethod::callStaticMethod called!-->str=%s," +
  18. " i=%d\n", str, i);
  19. }
  20. private void callInstanceMethod(String str, int i) {
  21. System.out.format("ClassMethod::callInstanceMethod called!-->str=%s, " +
  22. "i=%d\n", str, i);
  23. }
  24. }
  25. /* DO NOT EDIT THIS FILE - it is machine generated */
  26. #include <jni.h>
  27. #include <cstdio>
  28. /* Header for class com_example_myapplication_MainActivity */
  29. #ifndef _Included_com_example_myapplication_MainActivity
  30. #define _Included_com_example_myapplication_MainActivity
  31. #ifdef __cplusplus
  32. extern "C" {
  33. #endif
  34. /*
  35. * Class: com_example_myapplication_MainActivity
  36. * Method: callJavaStaticMethod
  37. * Signature: ()V
  38. */
  39. JNIEXPORT void JNICALL Java_com_example_myapplication_MainActivity_callJavaStaticMethod
  40. (JNIEnv *env, jclass cls){
  41. jclass clazz = NULL;
  42. jstring str_arg = NULL;
  43. jmethodID mid_static_method;
  44. // 1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
  45. clazz =(*env).FindClass("com/example/myapplication/ClassMethod");
  46. if (clazz == NULL) {
  47. return;
  48. }
  49. // 2、从clazz类中查找callStaticMethod方法
  50. mid_static_method = (*env).GetStaticMethodID(clazz,"callStaticMethod","(Ljava/lang/String;I)V");
  51. if (mid_static_method == NULL) {
  52. printf("找不到callStaticMethod这个静态方法。");
  53. return;
  54. }
  55. // 3、调用clazz类的callStaticMethod静态方法
  56. str_arg = (*env).NewStringUTF("我是静态方法");
  57. (*env).CallStaticVoidMethod(clazz,mid_static_method, str_arg, 100);
  58. // 删除局部引用
  59. (*env).DeleteLocalRef(clazz);
  60. (*env).DeleteLocalRef(str_arg);
  61. }
  62. /*
  63. * Class: com_example_myapplication_MainActivity
  64. * Method: callJavaInstaceMethod
  65. * Signature: ()V
  66. */
  67. JNIEXPORT void JNICALL Java_com_example_myapplication_MainActivity_callJavaInstaceMethod
  68. (JNIEnv *env, jclass cls){
  69. jclass clazz = NULL;
  70. jobject jobj = NULL;
  71. jmethodID mid_construct = NULL;
  72. jmethodID mid_instance = NULL;
  73. jstring str_arg = NULL;
  74. // 1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
  75. clazz = (*env).FindClass("com/example/myapplication/ClassMethod");
  76. if (clazz == NULL) {
  77. printf("找不到'com.study.jnilearn.ClassMethod'这个类");
  78. return;
  79. }
  80. // 2、获取类的默认构造方法ID
  81. mid_construct = (*env).GetMethodID(clazz, "<init>","()V");
  82. if (mid_construct == NULL) {
  83. printf("找不到默认的构造方法");
  84. return;
  85. }
  86. // 3、查找实例方法的ID
  87. mid_instance = (*env).GetMethodID( clazz, "callInstanceMethod", "(Ljava/lang/String;I)V");
  88. if (mid_instance == NULL) {
  89. return;
  90. }
  91. // 4、创建该类的实例
  92. jobj = (*env).NewObject(clazz,mid_construct);
  93. if (jobj == NULL) {
  94. printf("在com.study.jnilearn.ClassMethod类中找不到callInstanceMethod方法");
  95. return;
  96. }
  97. // 5、调用对象的实例方法
  98. str_arg = (*env).NewStringUTF("我是实例方法");
  99. (*env).CallVoidMethod(jobj,mid_instance,str_arg,200);
  100. // 删除局部引用
  101. (*env).DeleteLocalRef(clazz);
  102. (*env).DeleteLocalRef(jobj);
  103. (*env).DeleteLocalRef(str_arg);
  104. };
  105. #ifdef __cplusplus
  106. }
  107. #endif
  108. #endif

CC++ 访问 Java 实例变量和静态变量

  1. public class MainActivity extends AppCompatActivity {
  2. static {
  3. System.loadLibrary("HelloWorld");
  4. }
  5. private native static void accessInstanceField(ClassField obj);
  6. private native static void accessStaticField();
  7. @Override
  8. protected void onCreate(Bundle savedInstanceState) {
  9. super.onCreate(savedInstanceState);
  10. setContentView(R.layout.activity_main);
  11. ClassField obj = new ClassField();
  12. obj.setNum(10);
  13. obj.setStr("Hello");
  14. // 本地代码访问和修改ClassField为中的静态属性num
  15. accessStaticField();
  16. accessInstanceField(obj);
  17. // 输出本地代码修改过后的值
  18. System.out.println("In Java--->ClassField.num = " + obj.getNum());
  19. System.out.println("In Java--->ClassField.str = " + obj.getStr());
  20. }
  21. }
  22. public class ClassField {
  23. private static int num;
  24. private String str;
  25. public int getNum() {
  26. return num;
  27. }
  28. public void setNum(int num) {
  29. ClassField.num = num;
  30. }
  31. public String getStr() {
  32. return str;
  33. }
  34. public void setStr(String str) {
  35. this.str = str;
  36. }
  37. }
  38. /* DO NOT EDIT THIS FILE - it is machine generated */
  39. #include <jni.h>
  40. #include <cstdio>
  41. /* Header for class com_example_myapplication_MainActivity */
  42. #ifndef _Included_com_example_myapplication_MainActivity
  43. #define _Included_com_example_myapplication_MainActivity
  44. #ifdef __cplusplus
  45. extern "C" {
  46. #endif
  47. /*
  48. * Class: com_example_myapplication_MainActivity
  49. * Method: accessInstanceField
  50. * Signature: (Lcom/example/myapplication/ClassField;)V
  51. */
  52. JNIEXPORT void JNICALL Java_com_example_myapplication_MainActivity_accessInstanceField
  53. (JNIEnv *env, jclass cls, jobject obj){
  54. jclass clazz;
  55. jfieldID fid;
  56. jstring j_str;
  57. jstring j_newStr;
  58. const char *c_str = NULL;
  59. // 1.获取AccessField类的Class引用
  60. clazz = (*env).GetObjectClass(obj);
  61. if (clazz == NULL) {
  62. return;
  63. }
  64. // 2. 获取AccessField类实例变量str的属性ID
  65. fid = (*env).GetFieldID(clazz,"str", "Ljava/lang/String;");
  66. if (clazz == NULL) {
  67. return;
  68. }
  69. // 3. 获取实例变量str的值
  70. j_str = (jstring)(*env).GetObjectField(obj,fid);
  71. // 4. 将unicode编码的java字符串转换成C风格字符串
  72. c_str = (*env).GetStringUTFChars(j_str,NULL);
  73. if (c_str == NULL) {
  74. return;
  75. }
  76. printf("In C--->ClassField.str = %s\n", c_str);//没有打印 In c--->ClassField.str=Hello
  77. (*env).ReleaseStringUTFChars( j_str, c_str);
  78. // 5. 修改实例变量str的值
  79. j_newStr = (*env).NewStringUTF("This is C String");
  80. if (j_newStr == NULL) {
  81. return;
  82. }
  83. (*env).SetObjectField( obj, fid, j_newStr);
  84. // 6.删除局部引用
  85. (*env).DeleteLocalRef( clazz);
  86. (*env).DeleteLocalRef( j_str);
  87. (*env).DeleteLocalRef( j_newStr);
  88. };
  89. /*
  90. * Class: com_example_myapplication_MainActivity
  91. * Method: accessStaticField
  92. * Signature: ()V
  93. */
  94. JNIEXPORT void JNICALL Java_com_example_myapplication_MainActivity_accessStaticField
  95. (JNIEnv *env, jclass cls){
  96. jclass clazz;
  97. jfieldID fid;
  98. jint num;
  99. //1.获取ClassField类的Class引用
  100. clazz = (*env).FindClass("com/example/myapplication/ClassField");
  101. if (clazz == NULL) { // 错误处理
  102. return;
  103. }
  104. //2.获取ClassField类静态变量num的属性ID
  105. fid = (*env).GetStaticFieldID( clazz, "num", "I");
  106. if (fid == NULL) {
  107. return;
  108. }
  109. // 3.获取静态变量num的值
  110. num = (*env).GetStaticIntField(clazz,fid);
  111. printf("In C--.ClassField.num = %d\n", num);//没有打印 In c--->ClassField.num=10
  112. // 4.修改静态变量num的值
  113. (*env).SetStaticIntField( clazz, fid, 80);
  114. // 删除属部引用
  115. (*env).DeleteLocalRef(clazz);
  116. };
  117. #ifdef __cplusplus
  118. }
  119. #endif
  120. #endif

构造方法和父类实例方法

  1. public class Animal {
  2. protected String name;
  3. public Animal(String name) {
  4. this.name = name;
  5. System.out.println("Animal Construct call...");
  6. }
  7. public String getName() {
  8. System.out.println("Animal.getName Call...");
  9. return this.name;
  10. }
  11. public void run() {
  12. System.out.println("Animal.run...");
  13. }
  14. }
  15. public class Cat extends Animal {
  16. public Cat(String name) {
  17. super(name);
  18. System.out.println("Cat Construct call....");
  19. }
  20. @Override
  21. public String getName() {
  22. return "My name is " + this.name;
  23. }
  24. @Override
  25. public void run() {
  26. System.out.println(name + " Cat.run...");
  27. }
  28. }
  29. public class MainActivity extends AppCompatActivity {
  30. static {
  31. System.loadLibrary("HelloWorld");
  32. }
  33. public native static void callSuperInstanceMethod();
  34. @Override
  35. protected void onCreate(Bundle savedInstanceState) {
  36. super.onCreate(savedInstanceState);
  37. setContentView(R.layout.activity_main);
  38. callSuperInstanceMethod();
  39. }
  40. }
  41. /* DO NOT EDIT THIS FILE - it is machine generated */
  42. #include <jni.h>
  43. #include <cstdio>
  44. /* Header for class com_example_myapplication_MainActivity */
  45. #ifndef _Included_com_example_myapplication_MainActivity
  46. #define _Included_com_example_myapplication_MainActivity
  47. #ifdef __cplusplus
  48. extern "C" {
  49. #endif
  50. /*
  51. * Class: com_example_myapplication_MainActivity
  52. * Method: callSuperInstanceMethod
  53. * Signature: ()V
  54. */
  55. JNIEXPORT void JNICALL Java_com_example_myapplication_MainActivity_callSuperInstanceMethod
  56. (JNIEnv *env, jclass cls){
  57. jclass cls_cat;
  58. jclass cls_animal;
  59. jmethodID mid_cat_init;
  60. jmethodID mid_run;
  61. jmethodID mid_getName;
  62. jstring c_str_name;
  63. jobject obj_cat;
  64. const char *name = NULL;
  65. // 1、获取Cat类的class引用 com.example.myapplication
  66. cls_cat = (*env).FindClass( "com/example/myapplication/Cat");
  67. if (cls_cat == NULL) {
  68. return;
  69. }
  70. // 2、获取Cat的构造方法ID(构造方法的名统一为:<init>)
  71. mid_cat_init = (*env).GetMethodID(cls_cat, "<init>", "(Ljava/lang/String;)V");
  72. if (mid_cat_init == NULL) {
  73. return; // 没有找到只有一个参数为String的构造方法
  74. }
  75. // 3、创建一个String对象,作为构造方法的参数
  76. c_str_name = (*env).NewStringUTF("汤姆猫");
  77. if (c_str_name == NULL) {
  78. return; // 创建字符串失败(内存不够)
  79. }
  80. // 4、创建Cat对象的实例(调用对象的构造方法并初始化对象)
  81. obj_cat = (*env).NewObject(cls_cat, mid_cat_init,c_str_name);
  82. if (obj_cat == NULL) {
  83. return;
  84. }
  85. //-------------- 5、调用Cat父类Animal的run和getName方法 --------------
  86. cls_animal = (*env).FindClass("com/example/myapplication/Animal");
  87. if (cls_animal == NULL) {
  88. return;
  89. }
  90. //1: 调用父类的run方法
  91. mid_run = (*env).GetMethodID(cls_animal, "run", "()V"); // 获取父类Animal中run方法的id
  92. if (mid_run == NULL) {
  93. return;
  94. }
  95. // 注意:obj_cat是Cat的实例,cls_animal是Animal的Class引用,mid_run是Animal类中的方法ID
  96. (*env).CallNonvirtualVoidMethod(obj_cat, cls_animal, mid_run);
  97. //2:调用父类的getName方法
  98. // 获取父类Animal中getName方法的id
  99. mid_getName = (*env).GetMethodID(cls_animal, "getName", "()Ljava/lang/String;");
  100. if (mid_getName == NULL) {
  101. return;
  102. }
  103. c_str_name = static_cast<jstring>((*env).CallNonvirtualObjectMethod(obj_cat, cls_animal,
  104. mid_getName));
  105. name = (*env).GetStringUTFChars(c_str_name, NULL);
  106. printf("In C: Animal Name is %s\n", name);
  107. // 释放从java层获取到的字符串所分配的内存
  108. (*env).ReleaseStringUTFChars(c_str_name, name);
  109. quit:
  110. // 删除局部引用(jobject或jobject的子类才属于引用变量),允许VM释放被局部变量所引用的资源
  111. (*env).DeleteLocalRef(cls_cat);
  112. (*env).DeleteLocalRef(cls_animal);
  113. (*env).DeleteLocalRef(c_str_name);
  114. (*env).DeleteLocalRef(obj_cat);
  115. }
  116. #ifdef __cplusplus
  117. }
  118. #endif
  119. #endif

使用时缓存

  1. public class MainActivity extends AppCompatActivity {
  2. static {
  3. System.loadLibrary("HelloWorld");
  4. }
  5. private String str = "Hello";
  6. public native void accessField();
  7. public native String newString(char[] chars, int len);
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_main);
  12. accessField();
  13. char chars[] = new char[7];
  14. chars[0] = '1';
  15. chars[1] = '2';
  16. chars[2] = '3';
  17. chars[3] = '4';
  18. chars[4] = '5';
  19. chars[5] = '6';
  20. chars[6] = '7';
  21. String str = newString(chars, 6);
  22. System.out.println(str);
  23. }
  24. }
  25. /* DO NOT EDIT THIS FILE - it is machine generated */
  26. #include <jni.h>
  27. #include <cstdio>
  28. /* Header for class com_example_myapplication_MainActivity */
  29. #ifndef _Included_com_example_myapplication_MainActivity
  30. #define _Included_com_example_myapplication_MainActivity
  31. #ifdef __cplusplus
  32. extern "C" {
  33. #endif
  34. /*
  35. * Class: com_example_myapplication_MainActivity
  36. * Method: accessField
  37. * Signature: ()V
  38. */
  39. JNIEXPORT void JNICALL Java_com_example_myapplication_MainActivity_accessField
  40. (JNIEnv *env, jobject obj)
  41. {
  42. // 第一次访问时将字段存到内存数据区,直到程序结束才会释放,可以起到缓存的作用
  43. static jfieldID fid_str = NULL;
  44. jclass cls_AccessCache;
  45. jstring j_str;
  46. const char *c_str;
  47. cls_AccessCache = (*env).GetObjectClass(obj); // 获取该对象的Class引用
  48. if (cls_AccessCache == NULL) {
  49. return;
  50. }
  51. // 先判断字段ID之前是否已经缓存过,如果已经缓存过则不进行查找
  52. if (fid_str == NULL) {
  53. fid_str = (*env).GetFieldID(cls_AccessCache,"str","Ljava/lang/String;");
  54. // 再次判断是否找到该类的str字段
  55. if (fid_str == NULL) {
  56. return;
  57. } }
  58. j_str = static_cast<jstring>((*env).GetObjectField(obj, fid_str)); // 获取字段的值
  59. c_str = (*env).GetStringUTFChars(j_str, NULL);
  60. if (c_str == NULL) {
  61. return; // 内存不够
  62. }
  63. printf("In C:\n str = \"%s\"\n", c_str);
  64. (*env).ReleaseStringUTFChars( j_str, c_str); // 释放从从JVM新分配字符串的内存空间
  65. // 修改字段的值
  66. j_str = (*env).NewStringUTF( "12345");
  67. if (j_str == NULL) {
  68. return;
  69. }
  70. (*env).SetObjectField( obj, fid_str, j_str);
  71. // 释放本地引用
  72. (*env).DeleteLocalRef(cls_AccessCache);
  73. (*env).DeleteLocalRef(j_str);
  74. }
  75. /*
  76. * Class: com_example_myapplication_MainActivity
  77. * Method: newString
  78. * Signature: ([CI)Ljava/lang/String;
  79. */
  80. JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_newString
  81. (JNIEnv *env, jobject obj, jcharArray j_char_arr, jint len)
  82. {
  83. jcharArray elemArray;
  84. jchar *chars = NULL;
  85. jstring j_str = NULL;
  86. static jclass cls_string = NULL;
  87. static jmethodID cid_string = NULL;
  88. // 注意:这里缓存局引用的做法是错误,这里做为一个反面教材提醒大家,下面会说到。
  89. if (cls_string == NULL) {
  90. cls_string = (*env).FindClass("java/lang/String");
  91. if (cls_string == NULL) {
  92. return NULL;
  93. } }
  94. // 缓存String的构造方法ID
  95. if (cid_string == NULL) {
  96. cid_string = (*env).GetMethodID(cls_string, "<init>", "([C)V");
  97. if (cid_string == NULL) {
  98. return NULL;
  99. } }
  100. printf("In C array Len: %d\n", len);
  101. // 创建一个字符数组
  102. elemArray = (*env).NewCharArray(len);
  103. if (elemArray == NULL) {
  104. return NULL;
  105. }
  106. // 获取数组的指针引用,注意:不能直接将jcharArray作为SetCharArrayRegion函数最后一个参数
  107. chars = (*env).GetCharArrayElements(j_char_arr,NULL);
  108. if (chars == NULL) {
  109. return NULL;
  110. }
  111. // 将Java字符数组中的内容复制指定长度到新的字符数组中
  112. (*env).SetCharArrayRegion(elemArray, 0, len, chars);
  113. // 调用String对象的构造方法,创建一个指定字符数组为内容的String对象
  114. j_str = static_cast<jstring>((*env).NewObject(cls_string, cid_string, elemArray));
  115. // 释放本地引用
  116. (*env).DeleteLocalRef(elemArray);
  117. return j_str;
  118. }
  119. #ifdef __cplusplus
  120. }
  121. #endif
  122. #endif

类静态初始化缓存

  1. public class MainActivity extends AppCompatActivity {
  2. static {
  3. System.loadLibrary("HelloWorld");
  4. initIDs();
  5. }
  6. public static native void initIDs();
  7. public native void nativeMethod();
  8. public void callback() {
  9. System.out.println("AccessCache.callback invoked!");
  10. }
  11. @Override
  12. protected void onCreate(Bundle savedInstanceState) {
  13. super.onCreate(savedInstanceState);
  14. setContentView(R.layout.activity_main);
  15. nativeMethod();
  16. }
  17. }
  18. /* DO NOT EDIT THIS FILE - it is machine generated */
  19. #include <jni.h>
  20. #include <cstdio>
  21. /* Header for class com_example_myapplication_MainActivity */
  22. #ifndef _Included_com_example_myapplication_MainActivity
  23. #define _Included_com_example_myapplication_MainActivity
  24. #ifdef __cplusplus
  25. extern "C" {
  26. #endif
  27. jmethodID MID_AccessCache_callback;
  28. /*
  29. * Class: com_example_myapplication_MainActivity
  30. * Method: initIDs
  31. * Signature: ()V
  32. */
  33. JNIEXPORT void JNICALL Java_com_example_myapplication_MainActivity_initIDs
  34. (JNIEnv *env, jclass cls)
  35. {
  36. printf("initIDs called!!!\n");
  37. MID_AccessCache_callback = (*env).GetMethodID(cls,"callback","()V");
  38. }
  39. /*
  40. * Class: com_example_myapplication_MainActivity
  41. * Method: nativeMethod
  42. * Signature: ()V
  43. */
  44. JNIEXPORT void JNICALL Java_com_example_myapplication_MainActivity_nativeMethod
  45. (JNIEnv *env, jobject obj) {
  46. printf("In C Java_com_study_jnilearn_AccessCache_nativeMethod called!!!\n");
  47. (*env).CallVoidMethod(obj, MID_AccessCache_callback);
  48. }
  49. #ifdef __cplusplus
  50. }
  51. #endif
  52. #endif
JNI 局部引用、全局引用和弱全局引用
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/575218
推荐阅读
相关标签
  

闽ICP备14008679号