Android(安卓)Studio3.0开发JNI流程------JNI中字符串拼接的三种方式(C++)
16lz
2021-01-26
字符串拼接在java中很常见,比如拼接url路径,那么到了jni开发中怎么使用java中拼接字符串呢?不废话了啊,直接来个案例分析
我们将Android Studio3.0默认创建的工程文本显示从jni中拼接输出…
我们写一个简单的字符串返回的native方法,调用时给“Hello”参数,调用二种不同方式的拼接方法,在屏幕文本时输出内容为:Hello-World以及 Hello,欢迎来到JNI的世界!
以下两个方法是网上很多人采用的,但不是很友好,多次循环调用会出现崩溃。博主最近才发现的,所以在底部重新给出了新的字符串拼接的方式。
MainActivity.java类:
package fj.clover.jnistringbuilder;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.widget.TextView;public class MainActivity extends AppCompatActivity { static { System.loadLibrary("native-lib"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = (TextView) findViewById(R.id.sample_text); //调用native本地方法调用,实现在屏幕输出Hello-World! tv.setText(getString("Hello")); TextView tv1 = (TextView) findViewById(R.id.sample_text1); //调用native本地方法调用,实现在屏幕输出Hello,欢迎来到JNI的世界! tv1.setText(getString1("Hello")); } /** * 以下native方法主要是在JNI代码(C++)中实现getStr()方法内容 * @param str * @return */ public native String getString(String str); //方式一 public native String getString1(String str); //方式二 /*public String getStr(String str){ String string="-World!"; return str+string; }*/}
C++代码
#include #include #include /** * jstring转char函数... * @param env * @param jstr * @return */char *Jstring2CStr(JNIEnv *env, jstring jstr) { char *rtn = NULL; jclass clsstring = env->FindClass("java/lang/String"); jstring strencode = env->NewStringUTF("UTF-8"); //这里填写是工作空间的编码,若是默认中文则是GB2312 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); return rtn;}extern "C"/** * 字符串拼接的第一种方法 * @param env * @param instance * @param str_ * @return */JNIEXPORT jstring JNICALLJava_fj_clover_jnistringbuilder_MainActivity_getString(JNIEnv *env, jobject instance, jstring str_) { char *cstr = Jstring2CStr(env, str_); char *hellostr = "-World"; strcat(cstr, hellostr); //拼接两个字符串 return env->NewStringUTF(cstr);}extern "C"JNIEXPORT jstring JNICALL/** * 字符串拼接的第二种方法 * @param env * @param instance * @param str_ * @return */Java_fj_clover_jnistringbuilder_MainActivity_getString1(JNIEnv *env, jobject instance, jstring str_) { jstring message = env->NewStringUTF( strcat((char *) env->GetStringUTFChars(str_, JNI_FALSE), ",欢迎来到JNI的世界!")); return message;}
输出结果:
这个博客写的时间有点早了,最近发现,以上两种字符串拼接的方式,在线程中多次调用或者循环调用会造成程序出现异常崩溃的现象。
比如出现以下这种情况:
Fatal signal 11 (SIGSEGV), code 1, fault addr 0x646c726f in tid 20990 (RenderThread) [ 01-24 17:34:33.144 633: 633 W/ ] debuggerd: handling request: pid=20969 uid=10230 gid=10230 tid=20990
好了,讲重点的,直接给出新的字符串拼接的方法。
Java代码的native方法:public static native void ttttt(String str);
JNI动态注册方法:
void t5(JNIEnv *env, jclass type,jstring str_){ //第一种方法:<不好,字符串拼接会造成内存泄漏...> /** jstring message = env->NewStringUTF(strcat((char *) env->GetStringUTFChars(str_, JNI_FALSE), ",欢迎来到JNI的世界!")); LOGD("拼接后的字符串:%s ",env->GetStringUTFChars(message,0)); env->DeleteLocalRef(message); *///================================================================================================================================ //第二种方式:<不好,同上....> /** char *cstr = Jstring2CStr(env, str_); char *hellostr = "-World"; char *str3 = strcat(cstr, hellostr); //拼接两个字符串 LOGD("拼接后的字符串:%s ",str3); *///================================================================================================================================= //第三种方式:采用Java形式的字符串拼接方式 //invoke-virtual {p0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String; jclass String_clazz = env->FindClass("java/lang/String"); jmethodID concat_methodID = env->GetMethodID(String_clazz, "concat", "(Ljava/lang/String;)Ljava/lang/String;"); ///==================================== //需要在后面拼接的字符串... jstring str = env->NewStringUTF(",--- 新的一天,从\"心\"开始"); jobject str1 = env->CallObjectMethod(str_, concat_methodID, str); const char *chars = env->GetStringUTFChars((jstring)str1, 0); LOGD("拼接后字符 ===> %s ", chars); //释放内存 env->DeleteLocalRef(str); env->ReleaseStringUTFChars((jstring)str1,chars);}
在第三种方法中,采用的是Java中String拼接字符的方法,就是concat()函数的形式。这样可以避免在JNI中造成的内存泄漏。
更多相关文章
- Android——Intent在Activity的使用详解-下(隐式Intent与实现调用
- Unity与Android通信优化方案
- 实战:Android活动目录LiveFolder开发
- android打开一个activity时,什么情况使用finish()
- Android测试之旅之JUnit(一)
- Android调用照相机拍照
- Android(安卓)开发即时聊天工具 YQ :(一) Socket 初步
- Android实现上传拍下的照片到服务器
- android 模拟器调用系统照相机