您的位置:首页 > 移动开发 > Android开发

NDK开发 从入门到放弃(三:类型对应、字符串的操作、类型签名)

2016-10-31 11:55 288 查看

前言

我们之前的例子都是没有从Java代码中传参数给C++函数的,但是实际使用中大都是需要进行不同类型的数据传参与获取的,这就涉及到Java和C++的类型对应转换。主要涉及以下几点:

java方法里面将参数传入本地方法;

在本地方法里面创建java对象;

在本地方法里面return结果给java程序。

数据类型对应

从Java程序中传到本地方法中的原始类型可以直接使用,对应关系表如下所示:

Java 类型本地类型描述
booleanjbooleanC/C++8位整型
bytejbyteC/C++带符号的8位整型
charjcharC/C++无符号的16位整型
shortjshortC/C++带符号的16位整型
intjintC/C++带符号的32位整型
longjlongC/C++带符号的64位整型e
floatjfloatC/C++32位浮点型
doublejdoubleC/C++64位浮点型
voidvoidN/A
Objectjobject任何Java对象,或者没有对应java类型的对象
ClassjclassClass对象
Stringjstring字符串对象
Object[]jobjectArray任何对象的数组
boolean[]jbooleanArray布尔型数组
byte[]jbyteArray比特型数组
char[]jcharArray字符型数组
short[]jshortArray短整型数组
int[]jintArray整型数组
long[]jlongArray长整型数组
float[]jfloatArray浮点型数组
double[]jdoubleArray双浮点型数组

JNI字符串函数

常用的JNI函数将在后续介绍,这里给出其中的字符串操作函数的函数名以及相关描述。

JNI函数描述
GetStringChars
ReleaseStringChars
获得/释放一个Unicode格式的字符串指针,可能返回一个字符串的副本
GetStringUTFChars
ReleaseStringUTFChars
获得/释放一个UTF-8格式的字符串指针,可能返回一个字符串的副本
GetStringLength返回Unicode格式字符串的长度
GetStringUTFLength返回UTF-8格式字符串的长度
NewString根据Unicode格式的C字符串创建一个Java字符串
NewStringUTF根据UTF-8格式的C字符串创建一个Java字符串
GetStringCritical
ReleaseStringCritical
获得/释放一个Unicode格式的字符串指针,可能返回一个字符串的副本【在该函数对区间内,不能使用任何JNI函数】
GetStringRegion将Unicode格式的String复制到预分配的缓冲区中
GetStringUTFRegion将UTF-8格式的String复制到预分配的缓冲区中

类型签名

类型签名Java 类型
Zboolean
Bbyte
Cchar
Sshort
Iint
Jlong
Ffloat
Ddouble
Vvoid
Lfully-qualified-class ; 全限定的类
[ typetype[]
( arg-types ) ret-type方法类型
L
签名较为特殊,在类的全称前面加
L
,后面还要加上
;
。写参数类型签名时,类型之间没有空格没有
,
分隔符。

例如,Java方法:

boolean func(int n, String s, int[] arr);


具有以下类型签名:

(ILjava/lang/String;[I)Z


简单实例

我们用一个简单的动态注册JNI的例子来演示参数传递与字符串处理,从java函数中传递两个int型数据给C++函数,进行加法计算,然后在字符串中返回计算结果。

public class JNIDynamicUtils{
/**
* 调用C++代码的方法,计算两数相加的结果返回对应的字符串
* @return
*/
public static native String getSumFromJNI(int i1, int i2);

/**
* 加载so库或jni库
*/
static {
System.loadLibrary("JNI_DYNAMIC_ANDROID_TEST");
}
}


#include <stdio.h>
#include <jni.h>
#include <stdlib.h>

jstring calcSum(JNIEnv *env, jclass clazz, jint i1, jint i2) {
char result[50];
sprintf(result, " this is string from jni. result is %d", (i1 + i2));
return env->NewStringUTF(result);
}

/**
* JNINativeMethod由三部分组成:
* (1)Java中的函数名;
* (2)函数签名,格式为(输入参数类型)返回值类型;
*  ()Ljava/lang/String; (II)表示需要传两个int型参数,Ljava/lang/String;表示返回String,在对象类名(包括包名,‘/’间隔)前面加L,分号结尾
* (3)native函数名
*/
static JNINativeMethod gMethods[] = { {"getSumFromJNI", "(II)Ljava/lang/String;", (void *)calcSum }};

//System.loadLibrary过程中会自动调用JNI_OnLoad,在此进行动态注册
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
JNIEnv *env = NULL;
jint result = JNI_FALSE;

//获取env指针
if (jvm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) {
return result;
}
if (env == NULL) {
return result;
}
//获取类引用
jclass clazz = env->FindClass("com/xiaoyu/android/tools/JNIDynamicUtils");
if (clazz == NULL) {
return result;
}
//注册方法
if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < 0) {
return result;
}
//成功
result = JNI_VERSION_1_6;
return result;
}


int sprintf( char *buffer, const char *format, [ argument] … );

类似于printf,根据格式化字符串format,将后续参数列表中的参数逐个输出。不过输出目标不是标准输出终端,而是字符串buffer。

点击按钮时调用以下方法(tips:本打算用静态注册jni,后来为了用到类型签名,换成了动态注册。请忽略下面的
string from static jni
的错误。):

tvInfo.setText("--->string from static jni: " + JNIDynamicUtils.getSumFromJNI(3, 4));


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ndk android