XmlPullParser.getInputEncoding()在Android上的API11 +和

2019-08-31 06:07发布

我开发我的Android应用程序,使数据备份和恢复的新功能。 我使用的XML文件来备份数据。 这是一段代码,设置编码的输出文件:

XmlSerializer serializer = Xml.newSerializer();
FileWriter fileWriter = new FileWriter(file, false);
serializer.setOutput(fileWriter);
serializer.startDocument("UTF-8", true);
[... Write data to the file....]

这是我尝试从一个XML文件导入数据。 首先,我检查,如果编码是正确的:

XmlPullParser parser = Xml.newPullParser();
FileReader reader = new FileReader(file);
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(reader);
if(!"UTF-8".equals(parser.getInputEncoding())) {
    throw new IOException("Incorrect file encoding");
}
[... Read data from the file....]

在这里,我遇到了一个问题。 此代码工作正常在Android 2.3.3(两者装置和仿真器),编码被正确地检测为“UTF-8”。 但在API11 +版本(蜂窝,ICS,JB)抛出异常。 当我在调试模式下运行,这是我可以看到parser.getInputEncoding()返回null 。 我检查2.3.3和更高版本产生的实际的XML文件并且它们具有完全相同的标头: <?xml version='1.0' encoding='UTF-8' standalone='yes' ?>为什么getInputEncoding()上API11 +返回null?

其他的研究结果:

我发现有一种方法来正确检测使用API11 +设备文件编码FileInputStream代替FileReader是这样的:

XmlPullParser parser = Xml.newPullParser();
FileInputStream stream = new FileInputStream(file);
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(stream, null);
if(!"UTF-8".equals(parser.getInputEncoding())) {
    throw new IOException("Incorrect file encoding");
}
[... Read data from the file....]

在这种情况下getInputEncoding()适当地检测在API11 +仿真器和设备UTF-8编码的,但它在2.3.3返回null。 所以现在我可以在代码中插入一个叉使用的FileReader上API11 +和的FileInputStream上预API11:

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    parser.setInput(stream, null);
} else {
    parser.setInput(reader);
}

但是,什么是检查与XmlPullParser.getInputEncoding编码()的正确方法? 为什么不同的Android版本不同的表现取决于我用哪一个:或的FileInputStream的FileReader?

Answer 1:

一些试验和错误之后,我终于弄清楚是怎么回事。 因此,尽管该文件说:

从历史上看Android已经有这个接口的两个实现:通过XmlPullParserFactory.newPullParser KXmlParser()。 ExpatPullParser,经由Xml.newPullParser()。

无论哪种选择是好的。 本节中的示例使用ExpatPullParser,经由Xml.newPullParser()。

现实情况是,在旧的API,如2.3.3 Xml.newPullParser()返回ExpatPullParser对象。 而在冰淇淋三明治和多达返回KXmlParser对象。 正如我们可以看到从这个博客帖子 ,Android开发者知道这一点,因为2011年12月:

在冰淇淋三明治我们改变Xml.newPullParser()返回一个KxmlParser和删除我们ExpatPullParser类。

......但从来没有困扰更新的官方文档。

那么,你如何检索KXmlParser上的冰淇淋三明治之前的API对象? 简单:

XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser();

......其实这适用于Android,新旧的所有版本。 然后你提供一个FileInputStream你的解析器的setInput()方法,使默认编码null

FileInputStream stream = null;
stream = new FileInputStream(file);
parser.setInput(stream, null);

在此之后,原料药11和更高的,你可以调用parser.getInputEncoding()马上,它将返回正确的编码。 但在API11之前的版本,它会除非你叫parser.next返回null()首先,作为@Esailija正确他的回答中指出。 有趣的是,在API11 +调用next()没有任何负面影响无论如何,所以你可以放心地在所有版本中使用此代码:

parser.next();
String encoding = parser.getInputEncoding();

这将正确地返回“UTF-8”。



Answer 2:

FileReader和其他读者不检测编码。 他们只是用它可以巧合是UTF-8平台默认的编码。 它有没有关系文件的实际编码。

直到你读它足以看出你不能检测XML文件的编码encoding属性。

getInputEncoding()文档

如果inputEncoding为空并且分析器支持的编码检测功能 ,它必须返回检测到的编码

和:

如果setInput设置(阅读器)被调用,则返回null。

所以看来前11不支持这是通过使用可感知setInput(is, null) 。 我不知道你是如何得到"UTF-8"当使用setInput(reader)的文件说,它应该返回null

然后:

到明年第一个电话,如果XML声明存在后,此方法将返回了编码声明。

因此,在前期11,你可以尝试调用.next() intially之前调用.getInputEncoding



文章来源: Different behavior of XmlPullParser.getInputEncoding() on API11+ and pre-API11 versions of Android