浅谈动态注册JNI方法

之前的文章 《简单的手电筒程序(基于系统驱动节点)》,我们讲了如何通过JNI的方法修改文件节点,当时用的是静态注册的方法,即JAVA层在load so的时候按照 Java_<包名>_<类名>_<方法名> 的命名规则在Native层寻找对应的处理函数,但是这个方法虽然简单,但是也存在一定的弊端: 1. 初次调用native函数时需要根据命名规则建立对应关系,影响效率; 2. native函数过长的命名会造成管理不方便。所以接下来我们会介绍动态注册的方法。

所谓动态注册,其实就是我们自己在代码中建立映射关系,然后在JVM中注册,这样,Jvm就可以直接通过我们建立的函数映射表来调用对应的函数,而不用系统通过命名规范去搜索建立。

我们会以 《简单的手电筒程序(基于系统驱动节点)》 为例,将其改造成通过动态注册的方法,改造后如下:

#include<jni.h>  
#include<stdio.h>  
#include <fcntl.h>  
#include<sys/types.h>  
#include<sys/stat.h>  
#include"com_saberhao_bulbjni_BulbSwitch.h"  
#include <android/log.h>  
#include <unistd.h>  
#include "JNIHelp.h" 
  
#define LOG_TAG "BulbJNI"  
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)  
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)  
  
  
#define TRUNON "1"  
#define TRUNOFF "0"  
  
FILE *fp;  
int fd;  
int fd0;  
  
void Native_TurnOn (JNIEnv *, jobject)  
{  
        fd=open("/sys/class/camera/flash/rear_flash",O_WRONLY);  
        if(fd < 0)  
        {  
            LOGE("[turn on]open device error ");  
        }else{  
            LOGI("turn on the flash");  
            write(fd,TRUNON,sizeof(TRUNON));  
        }  
        close(fd);  
        if(fd0 < 0)  
        {  
            LOGE("[turn on]open test0 device error ");  
        }else{  
            //rewind(fp);  
            LOGI("turn on test0 the flash");  
            write(fd0,TRUNON,sizeof(TRUNON));  
        }  
        close(fd0);  
}  
  
void Native_TurnOff(JNIEnv *, jobject)  
{  
    fd=open("/sys/class/camera/flash/rear_flash",O_WRONLY);  
            if(fd < 0)  
            {  
                LOGE("[turn off]open device error ");  
            }else{  
                LOGI("turn off the flash");  
                write(fd,TRUNOFF,sizeof(TRUNOFF));  
            }  
            close(fd);  
} 

/** 
* 函数映射表
*/  
static JNINativeMethod gMethods[] = {  
    {
	"TurnOn",                   //Java 层函数名
	"()V", 						//(参数类型) 返回值
	(void*)Native_TurnOn        //Native 层函数类型
	},
	
	{
	"TurnOff",                   //Java 层函数名
	"()V", 						//(参数类型) 返回值
	(void*)Native_TurnOff        //Native 层函数类型
	},
}; 

int register_BulbJni(JNIEnv* env)
{
	return jniRegisterNativeMethods(env, "com/saberhao/bulbjni/BulbSwitch ", gMethods, NELEM(gMethods));
}

/* 
* System.loadLibrary("lib")时调用 
* 如果成功返回JNI版本, 失败返回-1 
*/  
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {  
    JNIEnv* env = NULL;  
    jint result = -1;  
  
    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
        return -1;  
    }  
    assert(env != NULL);  
  
  //JNI_OnLoad 中进行动态注册
    if (!register_BulbJni(env)) { 
        return -1;  
    }  
    //成功  
    result = JNI_VERSION_1_4;  
  
    return result;  
} 


有两个地方是要注意的:

1. jniRegisterNativeMethods和NELEM都是在头文件JNIHelp.h定义的, 需要添加 头文件

#include "JNIHelp.h" 


2.再Android.mk文件加上

LOCAL_SHARED_LIBRARIES +=libnativehelper

重点难点也是两个

1. JNINativeMethod 这个结构体,Java与JNI就是通过它来建立联系,它在jni.h中被定义,其结构内容如下:
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
第一个变量name是Java中函数的名字。
第二个变量signature,用字符串是描述了函数的参数和返回值
第三个变量fnPtr是函数指针,指向C函数


2. 当Java 层通过 System.loadLibrary加载完JNI的动态库后,会在库中查找是否存在 JNI_OnLoad方法,如果有,就调用它,我们将动态注册的方法在这里面完成,所以,如果要用动态注册的方法,我们都要实现 JNI_OnLoad函数。


参考文章:

http://blog.csdn.net/flydream0/article/details/7371692

http://blog.csdn.net/chenfeng0104/article/details/7088600



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值