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

相关推荐
summerkissyou19871 分钟前
Android - 摄像头 - hal - 开发教程,例子,常见问题,分析方法,解决方案
android
summerkissyou19871 小时前
Android 16 架构图
android
神龙天舞20011 小时前
MySQL 备库为什么会延迟好几个小时
android·数据库·mysql
码农coding4 小时前
android12 systemUI 之锁屏
android
圆山猫5 小时前
[Virtualization](三):RISC-V H-extension 与 Guest 执行模式
android·java·risc-v
爱笑鱼5 小时前
Binder(七):getCallingUid() 读到的是谁?clearCallingIdentity() 又清掉了什么?
android
2501_9159090611 小时前
iOS 应用反调试技详解术 检测调试器的原理与防护实践
android·ios·小程序·https·uni-app·iphone·webview
Lvan的前端笔记11 小时前
AndroidX 完全入门指南
android·androidx
帅次12 小时前
Android 应用高级面试:Window 近1年高频追问 18 题
android·面试·职场和发展
总捣什么乱112 小时前
MySQL MySQL是怎么保证主备一致的?
android·mysql·adb