Android JNI 开发进阶一 JavaString转C++String

上一篇对NDK开发进行了说明,如果没看的建议先看一下,这里就不说了
http://blog.csdn.net/u014289337/article/month/2017/04

转换中需要注意的事项:
一:c语言开发要注意是面向过程的开发,Java是面向对象的开发,在我们习惯了Java的时候在c中进行编程,要注意需要先定义后调用
二:在字符串输出要输出定义并且转换的字符串

直接上代码

public class JniTest {

    static {
        System.loadLibrary("jary");
    }
    static public native String AddStr(String strA, String strB);
    static public native int AddInt(int a, int b);
}

生成的.h文件(如何生成在上一篇文章中有详细步骤)

#include <jni.h>
/* Header for class encrypt_duojiankj_cn_jnitest_JniTest */

#ifndef _Included_encrypt_duojiankj_cn_jnitest_JniTest
#define _Included_encrypt_duojiankj_cn_jnitest_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     encrypt_duojiankj_cn_jnitest_JniTest
 * Method:    AddStr
 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_encrypt_duojiankj_cn_jnitest_JniTest_AddStr
  (JNIEnv *, jclass, jstring, jstring);

/*
 * Class:     encrypt_duojiankj_cn_jnitest_JniTest
 * Method:    AddInt
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_encrypt_duojiankj_cn_jnitest_JniTest_AddInt
  (JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

我们需要编写的.c文件

#include <jni.h>
#include <string.h>
#include "encrypt_duojiankj_cn_jnitest_JniTest.h"

/**
 * 从JAVA传字符串到C++
 * 上层JAVA数据类型String对应NDK为jstring类型,上层传参的方式和普通的java函数间调用并没有什么区别,重点是底层函数,
 * 如何将上层传来的jstring转化成本地可认并且可以操作的char *数组
 *
 * 返回值 char* 这个代表char数组的首地址
 *  Jstring2CStr 把java中的jstring的类型转化成一个c语言中的char 字符串
 */
char* Jstring2CStr(JNIEnv* env, jstring jstr) {
    char* rtn = NULL;
    jclass clsstring = (*env)->FindClass(env, "java/lang/String"); //String
    jstring strencode = (*env)->NewStringUTF(env, "GB2312"); // 得到一个java字符串 "GB2312"
    jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B"); //[ String.getBytes("gb2312");
    jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312");
    jsize alen = (*env)->GetArrayLength(env, barr); // byte数组的长度
    jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
    if (alen > 0) {
        rtn = (char*) malloc(alen + 1); //"\0"
        memcpy(rtn, ba, alen);
        rtn[alen] = 0;
    }
    (*env)->ReleaseByteArrayElements(env, barr, ba, 0); //
    return rtn;
}

JNIEXPORT jstring JNICALL Java_encrypt_duojiankj_cn_jnitest_JniTest_AddStr
        (JNIEnv *env, jclass org, jstring str1, jstring str2){
    char* cstr1 = Jstring2CStr(env, str1);
    char* cstr2 = Jstring2CStr(env, str2);
//    char arr[7] = { ' ', 'h', 'e', 'l', 'l', 'o', '\0' };
    strcat(cstr1, cstr2); //将cstr2合并到字符串cstr1 
    //从C++传字符串到java
    return (*env)->NewStringUTF(env, cstr1);//输出的是定义的类型
}

JNIEXPORT jint JNICALL Java_encrypt_duojiankj_cn_jnitest_JniTest_AddInt
        (JNIEnv *env, jclass org, jint a, jint b){
    return a + b;
}

总结:
上述这个简单的示例可以说明ndk开发中,Java是怎样将数据传递给C代码的了,程序中只是简单的介绍了一种数据类型string这是远远不够的,因为Java支持的数据类型比较多,这时候怎么办?好,有了上面的例子,我们可以举一反三了,在之前的博客中我也强调过ndk解压包下的jni.h这个文件的重要性,这个文件不仅仅定义了Java数据类型在C语言中的表示,看一下源码,就发现一种一一映射的关系:

......  
typedef uint8_t         jboolean;       /* unsigned 8 bits */  
typedef int8_t          jbyte;          /* signed 8 bits */  
typedef uint16_t        jchar;          /* unsigned 16 bits */  
typedef int16_t         jshort;         /* signed 16 bits */  
typedef int32_t         jint;           /* signed 32 bits */  
typedef int64_t         jlong;          /* signed 64 bits */  
typedef float           jfloat;         /* 32-bit IEEE 754 */  
typedef double          jdouble;        /* 64-bit IEEE 754 */  
#else  
typedef unsigned char   jboolean;       /* unsigned 8 bits */  
typedef signed char     jbyte;          /* signed 8 bits */  
typedef unsigned short  jchar;          /* unsigned 16 bits */  
typedef short           jshort;         /* signed 16 bits */  
typedef int             jint;           /* signed 32 bits */  
typedef long long       jlong;          /* signed 64 bits */  
typedef float           jfloat;         /* 32-bit IEEE 754 */  
typedef double          jdouble;        /* 64-bit IEEE 754 */  
......

另外还有一个非常重要的结构体JNINativeInterface,这里面定义了很多C函数,只要看懂大致意思就可以试着去调用这些函数,这些函数在native开发中显得特别重要:

    jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize);  
    jbyteArray    (*NewByteArray)(JNIEnv*, jsize);  
    jcharArray    (*NewCharArray)(JNIEnv*, jsize);  
    jshortArray   (*NewShortArray)(JNIEnv*, jsize);  
    jintArray     (*NewIntArray)(JNIEnv*, jsize);  
    jlongArray    (*NewLongArray)(JNIEnv*, jsize);  
    jfloatArray   (*NewFloatArray)(JNIEnv*, jsize);  
    jdoubleArray  (*NewDoubleArray)(JNIEnv*, jsize);  

    jboolean*   (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*);  
    jbyte*      (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*);  
    jchar*      (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*);  
    jshort*     (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*);  
    jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);  
    jlong*      (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*);  
    jfloat*     (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*);  
    jdouble*    (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*);  

源码比较长,有兴趣的朋友自己翻看一下,这里只贴部分

源码在这里
http://download.csdn.net/detail/u014289337/9825153

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值