Android | StandardCharsets.UTF_8.toString() 遇到的兼容问题记录

在Android开发中,处理字符串编码和解码是非常常见的需求。标准库中的 java.nio.charset.StandardCharsets 提供了方便且安全的字符集常量,尤其是 StandardCharsets.UTF_8,被广泛用于网络通信、文件读写等场景。然而,在开发过程中,遇到了一个关于 StandardCharsets.UTF_8.toString() 的兼容性问题,该问题在Android 6.0及以下版本中会导致 URLEncoderURLDecoder 的编码解码出现异常。本文记录一下遇到的这个问题。

问题描述

在Android 6.0及以下版本中,调用 StandardCharsets.UTF_8.toString() 返回的并不是预期的 "UTF-8" 字符串,而是返回了类似于 java.nio.charset.CharsetICUUTF-8 的字符串。这会导致 URLEncoder.encode()URLDecoder.decode() 方法无法正确识别字符集,从而抛出 java.nio.charset.IllegalCharsetNameException 异常。

以下是一个典型的示例代码(注意下面是错误写法):

kotlin 复制代码
import java.net.URLEncoder
import java.net.URLDecoder
import java.nio.charset.StandardCharsets

val encoded = URLEncoder.encode("hello world!", StandardCharsets.UTF_8.toString())
val decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8.toString())

在Android 6.0及以下版本中运行上述代码会抛出以下异常:

ini 复制代码
java.nio.charset.IllegalCharsetNameException: java.nio.charset.CharsetICU[UTF-8]

问题原因

导致这个问题的原因在于 StandardCharsets.UTF_8.toString() 的实现。在Android 6.0及以下版本中,toString() 方法返回了字符集对象的内部表示,而不是字符集名称。这在7.0版本及以上系统中得到了修复,toString() 方法被修改为调用 name() 方法,从而返回正确的字符集名称 "UTF-8"。

Android 6.0及以下版本的实现

来看下对应的Charset.java类:

Android 7.0及以上版本的实现

在7.0以上,toString()直接返回name()从而得到正确的字符集名称"UTF-8"。

java 复制代码
/**
 * Returns this charset's canonical name.
 *
 * @return  The canonical name of this charset
*/
public final String name() {
     return name;
} 

解决方案

为了兼容Android 6.0及以下版本,需要避免使用 StandardCharsets.UTF_8.toString() 方法。可以直接使用字符串 "UTF-8"或者直接调用StandardCharsets.UTF_8.name()。这样可以确保在所有版本都能正确地进行编码和解码操作。

示例代码

以下是修改后的示例代码,直接使用 "UTF-8" 字符串:

kotlin 复制代码
import java.net.URLEncoder
import java.net.URLDecoder

val encoded = URLEncoder.encode("hello world!", "UTF-8")
val decoded = URLDecoder.decode(encoded, "UTF-8")

或者是:
val encoded = URLEncoder.encode("hello world!", StandardCharsets.UTF_8.name())
val decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8.name())

完整解决方案

可以封装一个工具类来处理编码和解码操作,确保兼容性和可维护性。以下是一个完整的工具类示例:

kotlin 复制代码
object EncodingUtil {

    private const val CHARSET_UTF_8 = "UTF-8"

    /**
     * URL encode the given string using UTF-8 charset.
     */
    fun urlEncode(value: String): String {
        return URLEncoder.encode(value, CHARSET_UTF_8)
    }

    /**
     * URL decode the given string using UTF-8 charset.
     */
    fun urlDecode(value: String): String {
        return URLDecoder.decode(value, CHARSET_UTF_8)
    }
}

使用方式:

kotlin 复制代码
val encoded = EncodingUtil.urlEncode("hello world!")
val decoded = EncodingUtil.urlDecode(encoded)

总结一下,StandardCharsets.UTF_8.toString() 在Android 6.0及以下版本中的兼容性问题可以通过直接使用"UTF-8"字符串或者StandardCharsets.UTF_8.name()的方式来优化。

相关推荐
Android-Flutter4 小时前
android kotlin launch 源码分析
android·kotlin
Android-Flutter5 小时前
android kotlin 状态机 Continuation 详解
android·kotlin
Zha0Zhun6 小时前
Jetpack Compose 实现 iOS 风格 3D WheelPicker
android
深念Y7 小时前
RIO-UL00(EMUI 4.1 / Android 6.0.1 / arm64)开机自启动 sshd
android·linux·华为·安卓·chroot·sshd·emui
爱和冰阔落7 小时前
【MySQL 慢查询排查实战】列表接口逐渐变慢时,怎样从请求链路定位原因
android·数据库·mysql
hunterandroid1 天前
Android WebView JSBridge 治理实战:从线上白屏崩溃到协议化通信
android·前端
一个用户名i1 天前
【Compose 系列】第 1 篇:认识 Compose,为什么要学它
android·android jetpack
矩子01X1 天前
保姆级智能座舱测试入门:从 Android Automotive OS 到 SOA 服务的 7 层验证
android·自动化测试·网络协议·汽车测试
极客猴子1 天前
iPhone实时转写软件推荐:会议录音功能真实体验
android·人工智能·飞书