JNI_Onload的使用

JNI_Onload在执行system.loadLibrary()函数时被调用,主要用途

1.通过JNI_Onload告知VM,当前so库使用的JNI版本,最老的版本问JNI 1.1(JNI_Onload默认返回的是1.1版本),最新的JNI 1.4;其中JNI 1.4做了很多扩充。

2.可以在JNI_Onload中进行数据的初始化。

3.可以在JNI_Onload对java类中的native函数进行注册。java类是通过VM来调用本地方法,调用时需要通过VM在so库中寻找该本地函数,如果该本地函数需要频繁调用的话,会花费很多时间,可以在JNI_Onload调用registerNativeMethods,把native函数注册到VM中,减少寻找花费的时间。

实践:(1)在eclipse中创建一个android项目,新建一个JniMethod类,主要用来调用native方法。

JniMethod.java

package com.example.testjnionload;

public class JniMethod {
	static{
		System.loadLibrary("tjnionlod");
	}
	public native void printLog();
	public native void addFunc(int a,int b);
}
	  (2)在项目下新建一个jni文件夹,通过javah 生成JniMethod类中的native函数的声明头文件,如图1,2。
	
								1
	

图2

(3)在jni文件夹中新建一个jnimethod.c源文件,用于实现JNI_Onload和native函数。

jnimethod.c

#include <jni.h>
#include <android/log.h>
#include <stdio.h>
#define TAG "jnimethod"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)

#define JNIREG_CLASS "com/example/testjnionload/JniMethod" //native函数的java类名


JNIEXPORT void JNICALL native_printLog(JNIEnv *env, jobject obj){  //输出log信息
	LOGI("print my log");

}

JNIEXPORT void JNICALL native_addFunc(JNIEnv *env, jobject obj, jint a, jint b){ //在本地函数中实现加法

	int a1,b1,c1;
	a1=a;
	b1=b;
	c1=a1+b1;
	LOGI("addFunc return:%d",c1);

}
static JNINativeMethod gMethods[]={{"printLog","()V",(void*)native_printLog},
								  {"addFunc","(II)V",(void*)native_addFunc}							};      //需要注册到VM的native函数-->java中声明的native函数,函数JNI类型,本地对于的native函数名
static int registerNativeMethods(JNIEnv *env){		//native函数的注册
		jclass clazz;
		LOGI("in registerNativeMethods");
		clazz=(*env)->FindClass(env,JNIREG_CLASS);
		if(clazz==NULL){
			return JNI_FALSE;
		}

		if((*env)->RegisterNatives(env,clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0]))<0){  //注册函数
			return JNI_FALSE;
		}
		return JNI_TRUE;
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm,void* reserved){
	JNIEnv *env;
	jint result=-1;
	LOGI("in JNI_Onload");
	if((*vm)->GetEnv(vm,(void**)&env,JNI_VERSION_1_4)!=JNI_OK){

		return -1;
	}
//	assert(env!=NULL);

	if(!registerNativeMethods(env)){
		return -1;
	}
	result=JNI_VERSION_1_4;			//返回JNI 1.4版本信息给VM
	return result;
}
编写Android.mk文件


	
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE :=tjnionlod
LOCAL_SRC_FILES :=jnimethod.c

LOCAL_LDLIBS :=-llog

include $(BUILD_SHARED_LIBRARY)
	然后在eclipse中调用ndk-build进行编译,生成对于的so文件。
	在android项目的主activity中,调用该native函数,如图3。
	 图3
	JNI_Onload的基本使用就完成了。和JNI_Onload对应的还有JNI_Unload,JNI_Onload在加载so文件时调用的,JNI_Unload在卸载so时调用的。
	

	







                
`JNI_OnLoad` 是 Java Native Interface (JNI) 中的一个特殊函数,用于在加载本地库(如 `.so` 文件)时通知虚拟机该库使用JNI 版本,并执行一些初始化操作。当使用 `System.loadLibrary()` 加载本地库时,Java 虚拟机会自动调用此函数[^1]。 ### 用途 1. **指定 JNI 版本** 在 `JNI_OnLoad` 函数中,必须返回一个值以指示该库需要的 JNI 版本。例如,返回 `JNI_VERSION_1_6` 表示使用 JNI 1.6 版本。 2. **获取 JNIEnv 指针** `JNIEnv` 是一个指向 JNI 环境的指针,它提供了与 Java 环境交互的一系列函数。通过 `JNI_OnLoad` 可以获取到 `JNIEnv`,从而允许 C/C++ 代码访问和操作 Java 对象、方法和字段[^2]。 3. **注册本地方法** 在 `JNI_OnLoad` 中可以动态注册本地方法(Native Methods),而不需要依赖 Java 的 `native` 方法声明与命名规则。这种方法更灵活且易于维护。 ### 使用方式 #### 示例代码: ```c #include <jni.h> // JNI_OnLoad 函数定义 jint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env; // 获取 JNIEnv if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { return -1; // 如果获取失败,则返回错误码 } // 在此处可以进行本地方法的注册 return JNI_VERSION_1_6; // 返回所需的 JNI 版本 } ``` #### 功能解析: - `JavaVM *vm`: 表示 Java 虚拟机实例,可以通过它获取当前线程的 `JNIEnv`。 - `void *reserved`: 保留参数,通常不使用。 - `GetEnv()`: 用于获取当前线程的 `JNIEnv` 指针。 - 返回值: 必须返回支持的 JNI 版本,如 `JNI_VERSION_1_4`, `JNI_VERSION_1_6` 等。如果返回负数,表示加载失败[^1]。 ### 常见问题 1. **未实现 `JNI_OnLoad` 导致的问题** 如果没有正确实现 `JNI_OnLoad` 或者其返回了无效的 JNI 版本,可能会导致 `UnsatisfiedLinkError` 错误。例如: ``` java.lang.UnsatisfiedLinkError: JNI_ERR returned from JNI_OnLoad in ".../libdwEngineHw.so" ``` 这表明 `JNI_OnLoad` 返回了一个无效的 JNI 版本标识符(如 `JNI_ERR`),导致库加载失败[^3]。 2. **如何确保 `JNI_OnLoad` 正确工作** - 确保返回正确的 JNI 版本常量(如 `JNI_VERSION_1_6`)。 - 确保 `GetEnv()` 调用成功并获取有效的 `JNIEnv`。 - 避免在 `JNI_OnLoad` 中执行耗时或复杂的逻辑,以免影响应用启动性能。 3. **动态注册本地方法** 在 `JNI_OnLoad` 中可以调用 `RegisterNatives()` 方法来动态注册本地方法,避免手动匹配方法签名。例如: ```c static const JNINativeMethod methods[] = { {"nativeMethod", "()V", reinterpret_cast<void*>(my_native_function)}, }; jint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env; if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { return -1; } jclass clazz = env->FindClass("com/example/MyClass"); if (clazz == nullptr) { return -1; } if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) != JNI_OK) { return -1; } return JNI_VERSION_1_6; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值