数组
整形数组
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_example_ffmpegapplication_NativeStudy_ArrayTest(JNIEnv *env, jclass type,
jintArray array_) {
jintArray pArray = env->NewIntArray(10);
jsize length = env->GetArrayLength(array_);
// TODO 修改数组
jint *array = env->GetIntArrayElements(array_, NULL);
for (int i = 0; i < length; i++) {
array[i] = array[i] + 1;
}
env->ReleaseIntArrayElements(array_, array, 0);
jint nativeArray[length];
env->GetIntArrayRegion(array_, 0, length, nativeArray);
nativeArray[0] = 0;
nativeArray[1] = 9999;
nativeArray[2] = 8888;
env->SetIntArrayRegion(array_, 1, 3, nativeArray);
return array_;
}
打印:
01-19 16:34:29.810: E/www(22129): ArrayTest: 100
01-19 16:34:29.810: E/www(22129): ArrayTest: 0
01-19 16:34:29.810: E/www(22129): ArrayTest: 9999
01-19 16:34:29.810: E/www(22129): ArrayTest: 8888
01-19 16:34:29.810: E/www(22129): ArrayTest: 7
01-19 16:34:29.810: E/www(22129): ArrayTest: 8
01-19 16:34:29.810: E/www(22129): ArrayTest: 9
01-19 16:34:29.810: E/www(22129): ArrayTest: 10
- Get<Type>ArrayElements:获得指向Java数组元素的直接指针
- Release<Type>ArrayElements:释放指向Java数组元素的直接指针,最后一个参数是释放模式:
0:将内容复制回Java并释放native数组
JNI_COMMIT:将内容复制回Java但是不释放native数组,一般用于周期性的更新一个java数组
JNI_ABORT:释放native数组但是不将内容复制回Java - Get<Type>ArrayRegion:将Java数组复制到给定的C数组中。当数组很大时,这样复制数组会引起性能问题
- Set<Type>ArrayRegion:将C数组复制到Java数组
object数组
extern "C"
JNIEXPORT jobjectArray JNICALL
Java_com_example_ffmpegapplication_NativeStudy_StringArrayTest(JNIEnv *env, jclass type,
jobjectArray array) {
char *str1 = "Hello ";
// TODO 修改object数组
jsize length = env->GetArrayLength(array);
for (int i = 0; i < length; i++) {
jstring pJobject = (jstring) env->GetObjectArrayElement(array, i);
const char *string = env->GetStringUTFChars(pJobject, 0);
char str3[20];
strcpy(str3, str1);
strcat(str3, string);
jstring pJNewstring = env->NewStringUTF(str3);
env->SetObjectArrayElement(array, i, pJNewstring);
env->DeleteLocalRef(pJobject);
env->DeleteLocalRef(pJNewstring);
}
return array;
}
调用:
String[] array_string = {"java", "Android", "C", "C++"};
StringArrayTest(array_string);
for (int i = 0; i < array_string.length; i++) {
Log.e("", "array_stringTest: " + array_string[i]);
}
打印:
01-19 12:36:16.355: E/www(28743): array_stringTest: Hello java
01-19 12:36:16.355: E/www(28743): array_stringTest: Hello Android
01-19 12:36:16.355: E/www(28743): array_stringTest: Hello C
01-19 12:36:16.355: E/www(28743): array_stringTest: Hello C++
DeleteLocalRef:释放局部引用。在上面代码的for循环中,一直在创建局部引用对象,如果次数太多不去释放的话,就会造成局部引用泄露导致崩溃。
也可以批量的释放局部引用
// TODO 批量释放局部变量 通知JVM 您将使用超过 100 个本地引用。
if (env->EnsureLocalCapacity(100) == 0) { //确保至少给定数量的局部引用能在当前线程被创建。如果创建成功就返回0,否则就会返回一个负数
env->PushLocalFrame(100);
env->NewStringUTF(str1);
env->NewStringUTF(str1);
env->NewStringUTF(str1);
env->NewStringUTF(str1);
env->PopLocalFrame(NULL);
}
注意:
- 方法体中的一切引用都是局部的,包括:方法的Object参数,FindClass,GetObjectClass,GetObjectFeild,GetObjectArrayElement,NewStringUTF,NewLocalRef等
- native方法返回时,没有释放的局部引用会自动释放
全局变量
jclass mNativeStudyTest;
jfieldID mBooleanfieldID;
jfieldID mIntfieldID;
jmethodID mPlayNativeStudyTestID;
jmethodID mPlayNativeStudyTestStaticID;
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass pJclass = env->FindClass("com/example/ffmpegapplication/NativeStudyTest");
mNativeStudyTest = static_cast<jclass>(env->NewGlobalRef(pJclass));
mBooleanfieldID = env->GetFieldID(mNativeStudyTest, "mBooleanfield", "Z");
mIntfieldID = env->GetStaticFieldID(mNativeStudyTest, "mIntfield", "I");
mPlayNativeStudyTestID = env->GetMethodID(mNativeStudyTest, "playNativeStudyTest1", "()V");
mPlayNativeStudyTestStaticID = env->GetStaticMethodID(mNativeStudyTest,
"playNativeStudyTestStatic", "()V");
LOGE("%s","JNI_OnLoad end");
return JNI_VERSION_1_6;
}
JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return;
}
env->DeleteGlobalRef(mNativeStudyTest);
}
注意:
- 如果是Object对象,需要使用NewGlobalRef来赋值给全局变量,直接用等号是错误的
- 全局的Object对象需要使用DeleteGlobalRef释放
- jfieldID 和 jmethodID 不是Object对象,可以直接使用等号赋值
- JNI_OnLoad在java中使用System.loadLibrary时会调用,一般在这里面初始化,相对的是JNI_OnUnload
RegisterNatives注册本地方法
static jobject native_study_register_test1(JNIEnv *env, jobject thiz, jobject nativeStudyTest) {
LOGE("%s","调用方法native_study_register_test1");
jobject dpobj = env->AllocObject(mNativeStudyTest);
return dpobj;
}
static void native_study_register_test2(JNIEnv *env, jobject thiz, jobject nativeStudyTest, jint intfield) {
LOGE("%s","调用方法native_study_register_test2");
}
static void native_study_register_test3(JNIEnv *env, jobject thiz) {
LOGE("%s","调用方法native_study_register_test3");
}
static void native_study_register_test4(JNIEnv *env, jobject thiz) {
LOGE("%s","调用方法native_study_register_test4");
}
static JNINativeMethod methods[] = {
{"test1",
"(Lcom/example/ffmpegapplication/NativeStudyTest;)Lcom/example/ffmpegapplication/NativeStudyTest;",
(void*)native_study_register_test1},
{"test2",
"(Lcom/example/ffmpegapplication/NativeStudyTest;I)V",
(void*)native_study_register_test2},
{"test3",
"()V",
(void*)native_study_register_test3},
{"test4",
"()V",
(void*)native_study_register_test4}
};
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
int register_method(JNIEnv *env) {
char* classPathName = "com/example/ffmpegapplication/NativeStudy";
jclass pJclass = env->FindClass(classPathName);
LOGE("%s%d","register_method ", NELEM(methods));
jint result = env->RegisterNatives(pJclass, methods, NELEM(methods));
LOGE("%s","register_method end");
return result;
}
java代码
public native NativeStudyTest test1(NativeStudyTest nst);
public native void test2(NativeStudyTest nst, int i);
public native void test3();
public native void test4();
网友评论