Blankj / Blankj/AndroidUtilCode

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

Open
#1,848 0 comments 0 reactions 1 assignee Claimed by @Blankj View on GitHub
bug
Dominant language
Java
Stars
33.6k
Forks
10.6k
PR merge metrics
No merged PRs in 30d

Description

## 描述 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

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.