Android Studio3.0开发JNI流程------JNI中字符串拼接的三种方式(C++)

字符串拼接在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 JNICALL
Java_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;
}

输出结果:
Android Studio3.0开发JNI流程------JNI中字符串拼接的三种方式(C++)_第1张图片

这个博客写的时间有点早了,最近发现,以上两种字符串拼接的方式,在线程中多次调用或者循环调用会造成程序出现异常崩溃的现象。
比如出现以下这种情况:

 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,Studio,Android,jni)