android ndk 入门学习2
2015-08-13 13:32
417 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/BinSharp/article/details/47611259
Java Native Interface
更多有关JNI的信息
1)字符串
在Java和C/C++使用String,常会导致性能问题。Java的Strng使用16位的Unicode字符(UTF-16),而许多C/C++函数使用char *作字符串用(C/C++中的字符串大部分情况下用ASCII或UTF-8)。也就是说,Java字符串必须转换成C/C++字符串才可以使用。
//Java (Myclass.java文件中) public class MyClass { public static native void doSomethingWithString(String s); } //JNI 粘合层(C文件中) void JNICALL Java_com_apress_proandroid_MyClass_doSomethingWithString (JNIEnv *env,jclass clazz, jstring s) { const char* str = (*env)->GetStringUTFChars(env, s, NULL); if (str != NULL) { // 用str字符串在这里做些事情 // todo // 记得释放字符串,不要犯内存泄漏这个常见的错误。 (*env)->ReleaseStringUTFChars(env, s, str); } }
JNI提供了多种方法来处理字符串,它们都用相同的方式完成大量工作,在使用过程中注意以下事项:
I) Java字符串必须被转换成C/C++字符串;
II) C/C++字符串必须释放。
内存分配从来不是免费午餐,应该在代码中尽可能使用GetStringRegion和GetStringUTFRegion。这样做,可以得到以下好处:
a)避免可能的内存分配;
b)复制String要用的一部分到预先分配的缓冲区(可能在栈上);
c)不需要释放字符串,避免了忘了释放字符串的风险。
2、访问域或方法
可以从JNI粘合层内访问Java对象或类的域和方法,但它不像访问域或调用C++对象或类的函数那样简单,要通过id访问Java或类的域和方法。访问域或调用方法时需要:
a)得到这一域或方法的id;
b)使用JNI函数设置/获取域或调用方法。
public class MyClass { static { System.loadLibrary("mylib"); getIds();//加载类时,只需加载一次id } public static int someInteger = 0; public static native void sayHelloToJNI(); public static void helloFromJNI() { Log.i("MyClass", "Greetings! someInteger=" + someInteger); } private static native void getIds(); }
对应的C文件
#include "com_wll_util_ndk_MyClass.h" static jfieldID someIntegerId; static jmethodID helloFromJNIId; /* * Class: com_wll_util_ndk_MyClass * Method: sayHelloToJNI * Signature: ()V */ JNIEXPORT void JNICALL Java_com_wll_util_ndk_MyClass_sayHelloToJNI (JNIEnv *env, jclass clazz) { // 增加someInteger jint value = (*env)->GetStaticIntField(env, clazz, someIntegerId); (*env)->SetStaticIntField(env, clazz, someIntegerId, value + 1); // 调用helloFromJNI (*env)->CallStaticVoidMethod(env, clazz, helloFromJNIId); } /* * Class: com_wll_util_ndk_MyClass * Method: getIds * Signature: ()V */ JNIEXPORT void JNICALL Java_com_wll_util_ndk_MyClass_getIds (JNIEnv *env, jclass clazz) { // 获取someInteger域和helloFromJNI方法的id someIntegerId = (*env)->GetStaticFieldID(env, clazz, "someInteger", "I"); helloFromJNIId = (*env)->GetStaticMethodID(env, clazz, "helloFromJNI", "()V"); }
出于性能方面的考量,不想每次访问域或调用方法时都去获取一次域或方法的id。虚拟机加载类时域和方法的id就被设置,只要类被加载,该id就有效。高效的方式是在类被加载时获取id,即在静态初始化块中获取。
JNI定义了大量用于访问域和调用方法的函数。
相关文章推荐
- 按着步骤来,学习Android NDK入门很简单
- 按着步骤来,学习Android NDK入门很简单
- Android NDK的入门学习Hello JNI
- 下面就介绍下Android NDK的入门学习过程(转)
- Android NDK开发入门学习笔记(图文教程,极其详尽)
- Android NDK的入门学习过程(安装和helloJNI例程)
- Android NDK的入门学习过程
- 按着步骤来,学习Android NDK入门很简单
- GTK入门学习:glade的介绍
- mysql入门学习
- git入门学习以及常用命令
- Android NDK开发(一)入门篇
- 入门学习-Python-小甲鱼学习资料-Day029-文件:一个任务
- 学习GAWK入门(整理)
- Qt入门学习小记——UDP收发解决汉字乱码问题
- GTK入门学习:Libglade 和 GtkBuilder 的区别使用
- 零基础入门深度学习(5) - 循环神经网络
- 大数据入门级学习:SQL与NOSQL数据库
- MVC入门学习笔记(二)
- 黑马程序员—Java程序入门学习日记-基础篇1