Android之jni调用java函数总结

来源:互联网 发布:淘宝助理无销售属性 编辑:程序博客网 时间:2024/05/22 03:03

1、先看之前jni的如何实现动态注册

先看我之间的例子 http://blog.csdn.net/u011068702/article/details/71375920 

 Android之JNI动态注册native方法和JNI数据简单使用
因为这里演示的jni调用java函数是基于这个例子改的,然后还有如何在jni里面加上日志可以看这篇博客

http://blog.csdn.net/u011068702/article/details/71852904 

 Android之jni日志如何输出


2、贴出相关代码

      1)、java文加如下、

package com.example.chenyu.test;public class JniClient {publicJniClient() {}public native String getStr();public native int addInt(int a, int b);/** * C调用java空方法 */public void nullMethod() {System.out.println("I am chenyu, from java");}/** * C调用java中的带两个int参数的方法 * * @param x * @param y * @return */public int add(int x, int y) {int result = x + y;System.out.println("result in java " + result);return result;}/** * C调用java中参数为String的方法 * * @param s */public String printString(String s) {String result = "I am chenyu, from java " + s;System.out.println(result);return result;}// 本地方法public native void callMethod1();public native void callMethod2();public native void callMethod3();}

这里写了3个jni方法,然后我们实现这3个jni方法调用上面的3个java方法


jni里面的代码如下

//// Created by chenyu on 5/7/17.//#include <stdlib.h>#include <string.h>#include <stdio.h>#include <jni.h>#include <assert.h>#include <log_help.h>//定义的时候要记得加上双引号 不是#define TAG JniClient#define TAG "JniClient"#define JNIREG_CLASS "com/example/chenyu/test/JniClient"//指定要注册的类jstring get_str(JNIEnv* env, jobject thiz) {    LOGD(TAG, "hello chenyu");    char * str = "this is first LOGD";    LOGD(TAG, "hello chenyu %s", str);    return (*env)->NewStringUTF(env, "I am chenyu, 动态注册JNI");}jint add_int(JNIEnv* env, jobject jobj, jint num1, jint num2) {    LOGD(TAG, "nums + num2 is %d", num1 + num2);    return num1 + num2;}void callMethod1(JNIEnv* env, jobject obj) {LOGD(TAG, "this is jni call1");//在C语言中调用Java的空方法    //1.找到java代码native方法所在的字节码文件    //jclass (*FindClass)(JNIEnv*, const char*);    jclass clazz = (*env)->FindClass(env, "com/example/chenyu/test/JniClient");    if(clazz == 0) {        LOGD(TAG, "find class error");        return;    }    LOGD(TAG, "find class success");    //2.找到class里面对应的方法    // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);    jmethodID method1 = (*env)->GetMethodID(env, clazz, "nullMethod", "()V");    if(method1 == 0) {        LOGD(TAG, "find callMethod1 error");        return;    }    LOGD(TAG, "find callMethod1 success");    //3.调用方法    //void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);    (*env)->CallVoidMethod(env, obj, method1);    LOGD(TAG, "callMethod1 called success");}void callMethod2(JNIEnv* env, jobject obj) {LOGD(TAG, "this is jni call2");    jclass clazz = (*env)->FindClass(env, "com/example/chenyu/test/JniClient");    if(clazz == 0) {        LOGD(TAG, "find class error");        return;    }    LOGD(TAG, "find class success");    //2.找到class里面对应的方法    // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);    jmethodID method2 = (*env)->GetMethodID(env, clazz, "add", "(II)I");    if(method2 == 0) {        LOGD(TAG, "find callMethod2 error");        return;    }    LOGD(TAG, "find callMethod2 success");    //3.调用方法    //void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);    int result = (*env)->CallIntMethod(env, obj, method2, 3, 5);    LOGD(TAG, "callMethod2 called success");    LOGD(TAG, "in java 3 + 5 is %d", result);}void callMethod3(JNIEnv* env, jobject obj) {LOGD(TAG, "this is jni call3");    jclass clazz = (*env)->FindClass(env, "com/example/chenyu/test/JniClient");    if (clazz == 0) {        LOGD(TAG, "find class error");        return;    }    LOGD(TAG, "find class success");    //2.找到class里面对应的方法    // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);    jmethodID method3 = (*env)->GetMethodID(env, clazz, "printString", "(Ljava/lang/String;)Ljava/lang/String;");    if(method3 == 0) {        LOGD(TAG, "find callMethod3 error");        return;    }    LOGD(TAG, "find callMethod3 success");    //3.调用方法    //void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);    jstring result = (*env)->CallObjectMethod(env, obj, method3, (*env)->NewStringUTF(env, "hello jni insert data"));    //(*env)->CallVoidMethod(env, obj, method3, "chenyu"); //如果用这个会出现 JNI ERROR (app bug): accessed stale global reference 0xb39533f2 (index 19708 in a table of size 248)    const char* result1 = (*env)->GetStringUTFChars(env, result, NULL);//将返回的java字符串转换为c字符串    LOGD(TAG, "callMethod3 called success result is %s", result1);}/*** 方法对应表*/static JNINativeMethod gMethods[] = {        {"getStr", "()Ljava/lang/String;", (void*)get_str},        {"addInt", "(II)I", (void*)add_int},        {"callMethod1", "()V", (void*)callMethod1},        {"callMethod2", "()V", (void*)callMethod2},        {"callMethod3", "()V", (void*)callMethod3},};/** 为某一个类注册本地方法*/static int registerNativeMethods(JNIEnv* env        , const char* className        , JNINativeMethod* gMethods, int numMethods) {    jclass clazz;    clazz = (*env)->FindClass(env, className);    if (clazz == NULL) {        return JNI_FALSE;    }    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {        return JNI_FALSE;    }    return JNI_TRUE;}/** 为所有类注册本地方法*/static int registerNatives(JNIEnv* env) {    return registerNativeMethods(env, JNIREG_CLASS, gMethods,                                 sizeof(gMethods) / sizeof(gMethods[0]));}/** System.loadLibrary("lib")时调用* 如果成功返回JNI版本, 失败返回-1*/JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {    LOGD(TAG, "this is jni start and will exec JNI_OnLoad methos");    JNIEnv* env = NULL;    jint result = -1;    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {        return -1;    }    assert(env != NULL);    if (!registerNatives(env)) {//注册        return -1;    }    //成功    result = JNI_VERSION_1_4;    return result;}

步骤为:

      1)、获取jclass

      2)、获取jmethodID

      3)、调用本地的Call*****Method(); 如果不清楚函数,可以查看这里 http://www.ceeger.com/Script/AndroidJNI/AndroidJNI.CallStaticIntMethod.html

      如果函数返回String类型的话我们要调用

jstring result = (*env)->CallObjectMethod(env, obj, method3, (*env)->NewStringUTF(env, "hello jni insert data"));
      如果是jstring类型转成char *类型,我们需要用这个函数

const char* result1 = (*env)->GetStringUTFChars(env, result, NULL)

还有就是char *转成jstring可以用看下面的函数

    /**     * 转换c中的字符串为java.lang.String,这个方法是从网上找到的,感谢原作者<a href="http://home.cnblogs.com/u/liangwind/">天末凉风</a>          */      jstring stoJstring(JNIEnv* env, const char* pat)      {              jclass strClass = (*env)->FindClass(env,"Ljava/lang/String;");              jmethodID ctorID = (*env)->GetMethodID(env,strClass, "<init>", "([BLjava/lang/String;)V");              jbyteArray bytes = (*env)->NewByteArray(env,strlen(pat));              (*env)->SetByteArrayRegion(env,bytes, 0, strlen(pat), (jbyte*)pat);              jstring encoding = (*env)->NewStringUTF(env,"utf-8");              return (jstring)(*env)->NewObject(env,strClass, ctorID, bytes, encoding);      }  

在C++里面,把jstring转化成string函数如下

static std::string jstring2str(JNIEnv* env, jstring jstr){    char*   rtn   =   NULL;    jclass   clsstring   =   env->FindClass("java/lang/String");    jstring   strencode   =   env->NewStringUTF("UTF-8");    jmethodID   mid   =   env->GetMethodID(clsstring,   "getBytes",   "(Ljava/lang/String;)[B");    jbyteArray   barr=   (jbyteArray)env->CallObjectMethod(jstr,mid,strencode);    jsize   alen   =   env->GetArrayLength(barr);    jbyte*   ba   =   env->GetByteArrayElements(barr,JNI_FALSE);    if(alen   >   0)    {        rtn   =   (char*)malloc(alen+1);        memcpy(rtn,ba,alen);        rtn[alen]=0;    }    env->ReleaseByteArrayElements(barr,ba,0);    std::string stemp(rtn);    free(rtn);    return   stemp;}

 

至于参数的详解,返回值,数据类型,我前面几篇博客已经讲解,这里就不详细说了


   


3、运行结果




4、总结


jni调用java函数简单步骤,在jni函数里面实现以下几个步骤

1)、获取jclass

2)、获取jmethodID

3)、调用本地的Call*****Method(); 如果不清楚函数

如果函数返回String类型的话我们要调用

jstring result = (*env)->CallObjectMethod(env, obj, method3, (*env)->NewStringUTF(env, "hello jni insert data"));
 如果是jstring类型转成char *类型,我们需要用这个函数
const char* result1 = (*env)->GetStringUTFChars(env, result, NULL)

0 0
原创粉丝点击