平台:android4.0
场景:客户反馈部分中文歌曲的ID3信息显示为乱码。
时间:2012.6
参考网址:http://bbs.chinaunix.net/thread-3777433-2-1.html
将android系统语言设置为英文后,把一首包含中文的ID3信息的歌曲拷贝到机器中,可能在播放此歌曲时看到ID3信息是乱码。
当以下两个条件同时出现时,在android系统上将必定出现此问题:
1.当前语言设置为英文或其他(非中文)。
2.拷贝进去的歌曲的ID3信息是通过GBK编码写入的。
原因分析:
系统通过MediaScanner扫描的时候,将先在MediaProvider中构建一个MediaScanner的对象,在这个过程中,将调用
MediaScanner scanner = new MediaScanner(this);
Locale locale = getResources().getConfiguration().locale;
if (locale != null) {
String language = locale.getLanguage();
String country = locale.getCountry();
String localeString = null;
if (language != null) {
if (country != null) {
scanner.setLocale(language + "_" + country);
} else {
scanner.setLocale(language);
}
}
}
即在扫描之前,将调用scanner的setLocale()函数。
此函数为native函数,其最终将设置native的client对象中保存的mLocaleEncoding变量的值。而在媒体库扫描中,主要支持了以下几种编码格式:
(1).kEncodingNone—0000,默认的格式(Unicode编码,应该是使用的UTF-8)
(2).kEncodingShiftJIS—0001,日文编码格式
(3).kEncodingGBK—0010,中文简体编码格式
(4).kEncodingBig5—0100,中文繁体编码格式
(5).kEncodingEUCKR—1000,韩文编码格式
而其中另一个经常使用的变量kEncodingAll为1111。
MediaScannerClient.cpp中的setLocale()的实现,就是根据java层设置的参数来进行编码格式的设定。
在非中文的语言设置下,必然是不会使用GBK编码(mLocaleEncoding默认值为kEncodingNone)。若歌曲的ID3信息是以GBK进行保存的,因此就出现了乱码!
请注意:我们在扫描并保存歌曲等信息的时候,将先调用到native的client对象的addStringTag()方法,若编码格式没有问题,则将在此函数中直接调用handleStringTag()进行了信息的添加保存。
但若编码格式存在问题,则函数将获取的信息保存到mNames的mValues中,然后在调用client.endFile()时,统一对信息的编码进行处理,尝试转换成合理的编码后再进行handleStringTag()的调用保存。
在addStringTag()和endFile()函数中,第一句都是这个判断:
if (mLocaleEncoding != kEncodingNone)
由此可见,mLocaleEncoding的重要性。
确切的说,是mLocaleEncoding在初始化以及被setLocale()设置两个方面的重要性!
问题出现,正是因为mLocaleEncoding初始化的值就是kEncodingNone,然后又是在英文环境下,setLocale()后的mLocaleEncoding的值依然是kEncodingNone,所以addStringTag()中就直接进行了GBK信息的UTF-8的保存。endFile()函数中不再有任何表示。
解决方法:
1.我们需要在非对应的环境下(例如,英文环境–中文编码),确保不能在addStringTag()中就直接添加。
—-可以改变mLocaleEncoding的初始值。
2.在endFile()中对信息编码进行转换的时候,尽量确保每一种语言能使用其对应的编码方式进行保存。
—-possibleEncodings()(比如说,中文环境下—GBK编码,以UTF-8保存的ID3信息是不会出现乱码的!这正是因为此函数的功劳,它将尽可能获取保存信息的编码格式,确认UTF-8不会被转换成GBK)
—-convertValues()函数