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.format会考虑本地的语言环境(该问题中,由于手机在设置里面切换语言环境为阿拉伯语,导致上面代码在format的时候将“0,500”转为阿拉伯语“٠,٥٠٠ ”数据库无法识别,结果导致异常):
format(Locale l, String format, Object… args) 使用指定的语言环境、格式字符串和参数返回一个格式化字符串。
format(String format, Object… args) 使用指定的格式字符串和参数返回一个格式化字符串。
后面又测试,发现如下写法不会导致上述问题:
开始觉得特别奇怪,调用相同的方法为什么有的会根据语言环境转换而有的则不会,查看了源码,发现源码中会对d,s分别处理,除了d和时间类型转换其他的类型都不会进行语言转换。猜想原因是各个国家的数字表示都不同,做了特殊处理。其实到底为啥数字和时间类型要根据语言切换我也不明白,反正源码就是这样写的。以下是源码:
以上只拿出了部分源码,大概都是这个意思,是通过localizeDigits这个方法根据ASCII将数字0-9转为对应语言的字符,如下:
总结:在使用String.format以及new SimpleDateFormat(“yyyy-MM-dd”)时候一定要注意处理语言问题,不然很可能引起系统无法识别的错误。处理方式一个是全局指定语音环境,一个是在调用方法时指定语言环境。
全局(自己的Application):
调用方法:
format(Locale l, String format, Object… args) 使用指定的语言环境、格式字符串和参数返回一个格式化字符串。
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) 使用指定的语言环境、格式字符串和参数返回一个格式化字符串。
相关文章推荐
- 黑莓ECLIPSE3.5开发环境不识别资源文件导致编译不通过解决方案附文件(系统语言问题)
- Ubuntu设置环境变量错误导致系统无法登录解决方法
- android studio环境下,语音识别在多平台so文件下,导致无法识别的问题
- Ubuntu设置环境变量错误导致系统无法登录解决方法
- win7最大内存设置问题,导致系统无法启动的解决方法
- ubuntu设置环境变量错误导致系统无法登陆解决方法
- 环境变量设置错误导致无法登陆系统
- ubuntu设置环境变量错误导致系统无法登录
- Ubuntu设置环境变量错误导致系统无法登录解决方法 [转]
- Ubuntu设置环境变量错误导致系统无法登录解决方法
- 【福分系统】 LINQ to Entities 不识别方法“System.DateTime ToDateTime(System.String)”,因此该方法无法转换为存储表达式。
- 关于使用LayoutParams清除设置以及DateFormat无法正确转换格式化日期的问题
- 系统环境变量设置问题造成Visual Studio的CustomBuild无法使用
- linux环境下时区无法设置(系统时间慢8个小时)的问题解决
- 解决虚拟内存设置错误导致的系统蓝屏无法启动问题
- ubuntu设置环境变量错误导致系统无法登录
- linux环境下时区无法设置(系统时间慢8个小时)的问题解决
- Ubuntu设置环境变量错误导致系统无法登录解决方法
- Ubuntu设置环境变量错误导致系统无法登录解决方法
- Ubuntu设置环境变量错误导致系统无法登录解决方法