Skip to content

NumberUtils formatting fails to update on system language change due to static ThreadLocal caching #1848

Description

@QiuYucheng2003

描述 Bug

NumberUtils 类使用静态 ThreadLocal (DF_THREAD_LOCAL) 缓存格式化对象。initialValue() 方法仅在线程首次调用时执行,捕获当时的 Locale.getDefault()。

如果用户在 App 运行过程中切换系统语言(例如从英语切换到德语),由于线程池中的线程已初始化,ThreadLocal 中的 DecimalFormat 不会重建,依然持有旧的 Locale 配置。这将导致数字格式化(如小数点符号 . vs ,)不一致,部分界面显示旧语言格式,部分显示新语言格式。

  • AndroidUtilCode 的版本: 1.29.0
    • 出现 Bug 的设备型号: All (通用逻辑问题)
      • 设备的 Android 版本: All

相关代码

// NumberUtils.java
private static final ThreadLocal DF_THREAD_LOCAL = new ThreadLocal() {
@OverRide
protected DecimalFormat initialValue() {
// 这里的 NumberFormat.getInstance() 使用了当时的 Locale.getDefault()
// 一旦缓存,后续 Locale 变更不会反映在这里
return (DecimalFormat) NumberFormat.getInstance();
}
};

public static DecimalFormat getSafeDecimalFormat() {
return DF_THREAD_LOCAL.get();
}

预期行为 (Expected Behavior) 当系统语言发生变化时,NumberUtils.format() 应当使用新的 Locale 进行格式化。

修复建议 (Suggested Fix) 建议在获取缓存时校验 Locale,或者直接移除 ThreadLocal(在 ART 虚拟机上 DecimalFormat 创建开销通常可接受)。

public static DecimalFormat getSafeDecimalFormat() {
DecimalFormat df = DF_THREAD_LOCAL.get();
// 检查当前 Locale 是否发生变化
if (!df.getDecimalFormatSymbols().getLocale().equals(Locale.getDefault())) {
df = (DecimalFormat) NumberFormat.getInstance();
DF_THREAD_LOCAL.set(df);
}
return df;
}

堆栈信息 (Stack Trace) 无崩溃 (No Crash),属于逻辑错误 (Logic Error)。

截图 N/A

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions