关于ZAKER 融媒体解决方案 合作 加入

XmlPullParser.getInputEncoding ( ) 在 Android 的 API11 和 AP.

CocoaChina 10-23

我正在为我的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 版本 ( Honeycomb,ICS,JB ) 上会引发异常 . 当我在调试模式下运行此程序时 , 我可以看到 parser.getInputEncoding ( ) 返回 null. 我检查了在 2.3.3 和更高版本上生成的实际 XML 文件 , 它们具有完全相同的标头:. 为什么 getInputEncoding ( ) 在 API11 上返回 null?

其他发现:

我发现有一种方法可以使用 FileInputStream 而不是 FileReader 正确检测 API11 设备上的文件编码 , 如下所示:

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. 因此 , 现在我可以在代码中插入派生叉 , 以在 API11 上使用 FileReader 和在 API11 之前的 FileInputStream 上使用:

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

但是 , 使用 XmlPullParser.getInputEncoding ( ) 检查编码的正确方法是什么?为什么不同版本的 Android 会根据我使用的哪个文件 ( FileInputStream 或 FileReader ) 而表现不同?

最佳答案

经过更多的试验和错误之后 , 我终于设法弄清楚了发生了什么 . 因此 , 尽管事实是the documentation表示:

Historically Android has had two implementations of this interface:

KXmlParser via XmlPullParserFactory.newPullParser ( ) .

ExpatPullParser, via Xml.newPullParser ( ) .

Either choice is fine. The example in this section uses ExpatPullParser, via Xml.newPullParser ( ) .

现实是 , 在较旧的 API ( 例如 2.3.3 Xml.newPullParser ( ) ) 上返回 ExpatPullParser 对象 . 在 Ice Cream Sandwich 上 , 它返回 KXmlParser 对象 . 从this blog post可以看出 ,Android 开发者自 2011 年 12 月以来就知道这一点:

In Ice Cream Sandwich we changed Xml.newPullParser ( ) to return a KxmlParser and deleted our ExpatPullParser class.

…但是从不费心去更新官方文档 .

那么 , 如何在 Ice Cream Sandwich 之前在 API 上检索 KXmlParser 对象?简单:

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

…实际上 , 这适用于所有新旧版本的 android. 然后 , 向解析器的 setInput ( ) 方法提供 FileInputStream, 而默认编码为 null:

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

之后 , 在 API 11 或更高版本上 , 您可以立即调用 parser.getInputEncoding ( ) , 它将返回正确的编码 . 但是在 API11 之前的版本中 , 除非您先调用 parser.next ( ) , 否则它将返回 null, 因为 @Esailija 在其答案中正确指出 . 有趣的是 , 在 API11 上调用 next ( ) 不会产生任何负面影响 , 因此您可以在所有版本上安全地使用此代码:

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

并且这将正确返回 " UTF-8".

以上内容由"CocoaChina"上传发布 查看原文

觉得文章不错,微信扫描分享好友

扫码分享