Android之jni调用java函数总结
来源:互联网 发布:淘宝助理无销售属性 编辑:程序博客网 时间:2024/05/22 03:03
1、先看之前jni的如何实现动态注册
先看我之间的例子 http://blog.csdn.net/u011068702/article/details/71375920
因为这里演示的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
- Android之jni调用java函数总结
- 《Android JNI》05 在JNI中调用Java的函数
- java调用JNI总结
- JNI学习总结之:java调用native函数以及native函数回调java类成员方法
- Android之webkit内核JNI层与Java层 函数互相调用方法
- 【转载】Android之webkit内核JNI层与Java层 函数互相调用方法
- Android 利用JNI调用Android Java代码函数
- Android JNI --函数调用大全
- JNI之 c/c++调用java构造函数
- JNI如何调用Java函数
- JNI调用java接口函数
- Android下用JNI让Java调用C函数
- cocos2dx3.3 android工程 Jni调用java函数
- Android使用NDK(从java调用本地函数'JNI')
- Android-JNI(5)-C语言调用Java函数
- Android NDK(JNI)学习总结一:Java代码中申明native函数-Java调用C函数,并在C函数中访问java类和方法、属性
- android 之 JNI 调用 NDK
- 转战Android之NDK(jni, java调用c/c++)
- Zabbix_zabbix数据库表各字段说明
- nginx+ffmpge+rtmp实现媒体流的直播
- android基础(Context)
- 无限极分类管理之子属性获取
- 面向对象—多态(3)
- Android之jni调用java函数总结
- 深入理解JavaScript系列(18):面向对象编程之ECMAScript实现(推荐)
- Docker容器和本机之间的文件传输。
- BZOJ 1935: [Shoi2007]Tree 园丁的烦恼
- 用微信/APP给你的 ESP32 配置热点密码
- 惠州学院-数据库实验4-数据库中数据视图的使用
- 我的THREE.js之旅02: 使用THREE.js加载OSM的地图
- mpi实现矩阵相乘
- C# 通过NPOI导入导出数据EXCEL