GetStringUTFChars和GetStringUTFRegion的使用示例

常用的字符串传递有2种方式 使用例程进行测试

示例一 GetStringUTFRegion【推荐使用】

#include <stdio.h>
// demo.cpp
jstring jni_debug_string(JNIEnv *jenv, jobject thiz, 
	jstring str){
	
	LOGI("[%s]START#1\n", __FUNCTION__);
	
	char outputbuf[128];
	char inputbuf[128];
	
	int len = jenv->GetStringLength(str);
	LOGI("[%s]GetStringLength:%d", __FUNCTION__, len);
	jenv->GetStringUTFRegion(str, 0, len, inputbuf);

	sprintf(outputbuf, "thanks %s", inputbuf);
	LOGI("[%s]inputbuf:%s", __FUNCTION__, inputbuf);
	LOGI("[%s]outputbuf:%s", __FUNCTION__, outputbuf);
	
	return jenv->NewStringUTF(outputbuf);	
}

示例二 GetStringUTFChars

#include <stdio.h>
// demo.cpp
jstring jni_debug_string(JNIEnv *jenv, jobject thiz, 
	jstring str){
	
	LOGI("[%s]START#2\n", __FUNCTION__);
	const char* str_input;
	jboolean isCopy = false;
	
	char outputbuf[128];
	//char inputbuf[128];
	
	str_input = jenv->GetStringUTFChars(str, &isCopy);
	
	LOGI("[%s]str_input:%s", __FUNCTION__, str_input);
	sprintf(outputbuf, "thanks %s", str_input);
	
	jenv->ReleaseStringUTFChars(str, str_input);
	
	LOGI("[%s]outputbuf:%s", __FUNCTION__, outputbuf);
	
	return jenv->NewStringUTF(outputbuf);	
}

例程分析
由2个实际示例可以看出

GetStringUTFRegion 需要预先定义一个空间 inputbuf 来存放从java中传递过来的字符串,
虽然是需要增加了一个变量(即空间)进行存放,但是变量由自己控制。

GetStringUTFChars 是接口内部分配内存的方式来获取一个空间来存放java过来的字符串,
也是相当于增加了一个空间,只是把申请内存空间的操作封装到接口里面实现,
所以需要 ReleaseStringUTFChars 来对接口内部申请的空间进行释放。

就两种方式比较,可以看作第二种方式就是把第一种方式的调用稍微封装一下进行使用,
把本应该由用户自己定义空间在存放变量的操作封装到接口内部,省去用户自己定义的操作。

这里更推荐是方式一,由用户自己定义的空间更为直观控制。

NewStringUTF 是由env向java层进行调用,
则相关的内存管理也是有java管理,相当于在java层 new String[len]; 不涉及到c++的内存申请。

安卓上层调用接口


findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
	
	@Override
	public void onClick(View v) {
		on_set_string();
	}
});

// public native String jni_debug_string(String str_in);

private void on_set_string() {
	String data;
	data = String.format("%s", "Android"); 
	data = jniclass.jni_debug_string(data);
	Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();
}

上层需要使用 String.format 进行文字的格式化,否则会提示报错
直接赋值时 data = “Android”;
提示错误 input is not valid Modified UTF-8: illegal start byte 0xf4

普通格式化 data = String.format(“Android”);
提示错误 input is not valid Modified UTF-8: illegal start byte 0xff

如果调用 jni_debug_string 之前使用过Log输出,结果也是正常不报错状态
Log.i(“MainActivity”, “data:” + data);

更推荐使用例程中的 String.format("%s", “Android”);

所以jni直接接收String数据类型时,必须进行格式化,
不然无法确认字符串的完整性导致错误。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是 JNI 中遍历 std::map 的示例代码: ```c++ JNIEXPORT void JNICALL Java_com_example_MapExample_mapIteration(JNIEnv *env, jobject obj, jobject mapObj) { // 获取 Map 的 class 对象 jclass mapClass = env->GetObjectClass(mapObj); // 获取 Map.entrySet() 方法的 ID jmethodID entrySetMethodID = env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;"); // 调用 Map.entrySet() 方法获取所有的键值对 jobject entrySetObj = env->CallObjectMethod(mapObj, entrySetMethodID); // 获取 Set 的 class 对象 jclass setClass = env->GetObjectClass(entrySetObj); // 获取 Set.iterator() 方法的 ID jmethodID iteratorMethodID = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;"); // 调用 Set.iterator() 方法获取迭代器 jobject iteratorObj = env->CallObjectMethod(entrySetObj, iteratorMethodID); // 获取 Iterator 的 class 对象 jclass iteratorClass = env->GetObjectClass(iteratorObj); // 获取 Iterator.hasNext() 方法的 ID jmethodID hasNextMethodID = env->GetMethodID(iteratorClass, "hasNext", "()Z"); // 获取 Iterator.next() 方法的 ID jmethodID nextMethodID = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;"); // 遍历 Map 中的所有键值对 while (env->CallBooleanMethod(iteratorObj, hasNextMethodID)) { // 调用 Iterator.next() 方法获取下一个键值对 jobject entryObj = env->CallObjectMethod(iteratorObj, nextMethodID); // 获取 Map.Entry 的 class 对象 jclass entryClass = env->GetObjectClass(entryObj); // 获取 Map.Entry.getKey() 方法的 ID jmethodID getKeyMethodID = env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;"); // 获取 Map.Entry.getValue() 方法的 ID jmethodID getValueMethodID = env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;"); // 调用 Map.Entry.getKey() 方法获取键 jstring keyObj = (jstring) env->CallObjectMethod(entryObj, getKeyMethodID); // 调用 Map.Entry.getValue() 方法获取值 jstring valueObj = (jstring) env->CallObjectMethod(entryObj, getValueMethodID); // 将键值转换为 C++ 字符串 const char* key = env->GetStringUTFChars(keyObj, NULL); const char* value = env->GetStringUTFChars(valueObj, NULL); // 输出键值对 printf("%s: %s\n", key, value); // 释放字符串所占用的内存 env->ReleaseStringUTFChars(keyObj, key); env->ReleaseStringUTFChars(valueObj, value); } } ``` 这段代码首先获取了 Map 对象的 class 对象,然后获取了 Map.entrySet() 方法的 ID,并调用该方法获取所有的键值对。接着获取了 Set 对象的 class 对象,以及 Set.iterator() 方法的 ID,并调用该方法获取迭代器。然后获取了 Iterator 对象的 class 对象,以及 Iterator.hasNext() 方法和 Iterator.next() 方法的 ID。最后通过迭代器遍历 Map 中的所有键值对,并获取每个键值对的键和值,将其转换为 C++ 字符串后输出。需要注意的是,遍历结束后需要释放字符串所占用的内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值