您的位置:首页 > 其它

String.format与手机设置的语言环境的关系导致语言转换系统无法识别闪退问题

2017-06-13 10:41 477 查看
问题原因:线上闪退日志突然出现同一个用户几千条闪退日志,且都是同一个闪退 no such column: ٥٠٠ (code 1): , while compiling: SELECT type, wid FROM MoPeibo LIMIT ٠,٥٠٠。调查发现٠,٥٠٠是阿拉伯语中的0,500。我们代码是使用String.format来将0和500这两个int类型的值转为string”0,500”。转换代码如下:

String limit = String.format("%d,%d", new Object[]{Integer.valueOf(offset), Integer.valueOf(500)});


也就是说,String.format会考虑本地的语言环境(该问题中,由于手机在设置里面切换语言环境为阿拉伯语,导致上面代码在format的时候将“0,500”转为阿拉伯语“٠,٥٠٠ ”数据库无法识别,结果导致异常):

format(Locale l, String format, Object… args) 使用指定的语言环境、格式字符串和参数返回一个格式化字符串。

format(String format, Object… args) 使用指定的格式字符串和参数返回一个格式化字符串。

后面又测试,发现如下写法不会导致上述问题:

String limit = String.format("%s,%s", String.valueOf(offset), String.valueOf(500));


开始觉得特别奇怪,调用相同的方法为什么有的会根据语言环境转换而有的则不会,查看了源码,发现源码中会对d,s分别处理,除了d和时间类型转换其他的类型都不会进行语言转换。猜想原因是各个国家的数字表示都不同,做了特殊处理。其实到底为啥数字和时间类型要根据语言切换我也不明白,反正源码就是这样写的。以下是源码:

if (token.isDefault()) {
switch (token.getConversionType()) {
case 's':
if (arg == null) {
return "null";
} else if (!(arg instanceof Formattable)) {
return arg.toString();
}
break;
case 'd':
boolean needLocalizedDigits = (localeData.zeroDigit != '0');
if (out instanceof StringBuilder && !needLocalizedDigits) {
if (arg instanceof Integer || arg instanceof Short || arg instanceof Byte) {
IntegralToString.appendInt((StringBuilder) out, ((Number) arg).intValue());
return null;
} else if (arg instanceof Long) {
IntegralToString.appendLong((StringBuilder) out, ((Long) arg).longValue());
return null;
}
}
if (arg instanceof Integer || arg instanceof Long || arg instanceof Short || arg instanceof Byte) {
String result = arg.toString();
return needLocalizedDigits ? localizeDigits(result) : result;
}
}
}


以上只拿出了部分源码,大概都是这个意思,是通过localizeDigits这个方法根据ASCII将数字0-9转为对应语言的字符,如下:

private CharSequence localizeDigits(CharSequence s) {
int length = s.length();
int offsetToLocalizedDigits = localeData.zeroDigit - '0';
StringBuilder result = new StringBuilder(length);
for (int i = 0; i < length; ++i) {
char ch = s.charAt(i);
if (ch >= '0' && ch <= '9') {
ch += offsetToLocalizedDigits;
}
result.append(ch);
}
return result;
}


总结:在使用String.format以及new SimpleDateFormat(“yyyy-MM-dd”)时候一定要注意处理语言问题,不然很可能引起系统无法识别的错误。处理方式一个是全局指定语音环境,一个是在调用方法时指定语言环境。

全局(自己的Application):

String languageToLoad  = "zh";
Locale locale = new Locale(languageToLoad);
Locale.setDefault(locale);
Configuration config = getResources().getConfiguration();
DisplayMetrics metrics = getResources().getDisplayMetrics();
config.locale= Locale.SIMPLIFIED_CHINESE;
getResources().updateConfiguration(config,metrics);


调用方法:

format(Locale l, String format, Object… args) 使用指定的语言环境、格式字符串和参数返回一个格式化字符串。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐