【问题标题】:4-byte wchar_t to String conversion using JNI使用 JNI 将 4 字节 wchar_t 转换为字符串
【发布时间】:2020-05-10 14:56:14
【问题描述】:

所以我有这个 CanvasView,它显示了我的应用程序的调试信息。它基本上是具有透明背景的叠加视图,因此画布中绘制的所有内容都漂浮在屏幕中。由于我需要来自返回 wchar_t* 的本机 c++ 的一些信息,我该如何使用 env->NewString,因为 android 现在使 wchar_t 为 4 个字节,而 jchar 为 2 个字节?

在我的库中调用本机 c++ 函数的 java 代码:

private static String get_Name();
private class CanvasView extends View{
    public CanvasView(Context context){
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Paint paintText = new Paint();
        paintText.setStyle(Paint.Style.FILL);
        paintText.setColor(Color.WHITE);
        paintText.setShadowLayer(5.5f, 0, 0, Color.BLACK);
        paintText.setTextSize(convertSizeToDp(7.5f));
        paintText.setTextAlign(Paint.Align.LEFT);

        paintText.drawText(get_Name(), x, y, paintText);


        // the rest of the code
        // ...
    }
}

get_Name 基本上返回一个来自NewString((const jchar* )myWchar, myLen)的jstring

当调用NewString 时,返回结果有时是非 unicode 字符串,甚至我的应用程序崩溃。

【问题讨论】:

  • 这能回答你的问题吗? Android Canvas.drawText
  • @TruthSeeker 不,我的问题是将 wchar_t* 转换为 jstring。
  • 如果我从 android.developer 网站了解 Paint 不会公开任何公共方法 drawText 但 Canvas。让它canvas.drawText(get_Name(), x, y, paintText);

标签: android c++ java-native-interface


【解决方案1】:

首先,使用 JNI 分配一个ByteBuffer:

wchar_t *input = ...;
jobject bb = env->NewDirectByteBuffer((void *) input, wcslen(input) * sizeof(wchar_t));

接下来,调用Charset.forName("UTF-32LE").decode(bb).toString():(每段为一个步骤)

jclass cls_Charset = env->FindClass("java/nio/charset/Charset");
jmethodID mid_Charset_forName = env->GetStaticMethodID(cls_Charset, "forName", "(Ljava/lang/String;)Ljava/nio/charset/Charset;");
jobject charset = env->CallStaticObjectMethod(cls_Charset, mid_Charset_forName, env->NewStringUTF("UTF-32LE"));

jmethodID mid_Charset_decode = env->GetMethodID(cls_Charset, "decode", "(Ljava/nio/ByteBuffer;)Ljava/nio/CharBuffer;");
jobject cb = env->CallObjectMethod(charset, mid_Charset_decode, bb);

jclass cls_CharBuffer = env->FindClass("java/nio/CharBuffer");
jmethodID mid_CharBuffer_toString = env->GetMethodID(cls_CharBuffer, "toString", "()Ljava/lang/String;");
jstring ret = env->CallObjectMethod(cb, mid_CharBuffer_toString);

return ret;

注意:这取决于您所在平台的字节序。从this answer 看来,所有Android 平台都是小端的。如果您在大端平台上,您可能需要改用UTF-32BE。

【讨论】:

    【解决方案2】:

    wchar_t 是 2 个字节的唯一平台是 Windows。在其他平台上,wchar_t 是 4 个字节。 env->NewString() 将 UTF-16 数据作为输入,因此在调用 env->NewString() 之前,您必须将 wchar_t 数据从 UTF-32 转换为 UTF-16。否则,您将不得不使用 JNI 调用 Java String 构造函数,该构造函数将 byte[] 数组和字符集作为输入,因此您可以直接从 UTF-32 数据创建字符串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-02
      • 2014-11-12
      • 1970-01-01
      • 2011-02-03
      • 1970-01-01
      • 2015-02-27
      • 2012-03-30
      相关资源
      最近更新 更多