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.CharsetICU[UTF-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()的方式来优化。

相关推荐
阿巴斯甜19 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker19 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952720 小时前
Andorid Google 登录接入文档
android
黄林晴21 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android
Jony_2 天前
Android 启动优化方案
android
阿巴斯甜2 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇2 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android