42

我想在我的资源文件中使用这个unicode 字符。

但无论我做什么,我都会以 dalvikvm 崩溃结束(使用 Android 2.3 和 4.2.2 测试):

W/dalvikvm( 8797): JNI WARNING: input is not valid Modified UTF-8: illegal start byte 0xf0
W/dalvikvm( 8797):              string: ''
W/dalvikvm( 8797):              in Landroid/content/res/StringBlock;.nativeGetString:(II)Ljava/lang/String; (NewStringUTF)
E/dalvikvm( 8797): VM aborting
F/libc    ( 8797): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1), thread 8797 (cz.ipex...)

我在我的资源文件中尝试了这些版本:

<string name="geolocation_icon" translatable="false">&#x1f4e1;</string> <!-- HTML -->
<string name="geolocation_icon" translatable="false">\uD83D\uDCE1</string> <!-- escaped unicode -->
<string name="geolocation_icon" translatable="false"></string> <!-- unicode character -->

请注意,在代码中的 Java String 中使用它可以正常工作:

final String geolocation_icon = "\uD83D\uDCE1";
4

2 回答 2

54

您的字符 ( U+1F4E1) 不在 Unicode BMP(基本多语言平面 - 范围从U+0000U+FFFF)之外。

不幸的是,Android 对非 BMP 字符的支持非常弱(如果有的话)。UTF-8非 BMP 字符的表示需要 4 个字节 ( 0xF0 0x9F 0x93 0xA1)。但是,AndroidUTF-8解析器最多只能理解 3 个字节(参见此处此处)。

当您使用UTF-16此字符的代理形式表示时,它适用于您:"\uD83D\uDCE1". 如果您能够UTF-16在 modified UTF-8(aka CESU-8) 中对每个代理字符进行编码 - 总共需要 6 个字节(UTF-8代理对的每个成员需要 3 个字节),那么这是可能的。但是,Android 也不CESU-8明确支持。

因此,您当前的解决方案 - 将源代码中的这个符号硬编码为代理UTF-16对似乎最简单,至少在 Android 开始完全支持 non-BMP 之前是这样UTF-8

更新:这似乎在 Android 6.0 中得到了部分修复。此提交已合并到 Android 6 中,并允许在 XML 资源中存在 4 字节 UTF-8 字符。它不是完美的解决方案 - 它只会自动将 4 字节 UTF-8 转换为适当的代理对。但是,它允许将它们从源代码移动到 XML 资源中。不幸的是,在您的应用程序可以停止支持除 6.0 及更高版本之外的任何 Android 版本之前,您无法使用此解决方案。

于 2013-05-28T10:40:02.037 回答
-1

这样做

不要在 strings.xml 中保留有问题的表情符号

以编程方式添加

<string name="hi_welcome_msg">Hi %1$s</string>

getString(R.string.hi_welcome_msg, user.getFullName() + " \uD83D\uDC4B" );
于 2019-08-28T11:29:57.753 回答