本文主要是介绍String.format与手机设置的语言环境的关系导致语言转换系统无法识别闪退问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
问题原因:线上闪退日志突然出现同一个用户几千条闪退日志,且都是同一个闪退 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) 使用指定的语言环境、格式字符串和参数返回一个格式化字符串。
这篇关于String.format与手机设置的语言环境的关系导致语言转换系统无法识别闪退问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!