您的位置:首页 > 移动开发 > Android开发

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定义了大量用于访问域和调用方法的函数。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: