2013-04-15 30 views
0

我正在爲我的android應用開發一項新功能來啓用數據備份和還原。我正在使用XML文件來備份數據。這是一段代碼,設置編碼的輸出文件:API11 +和Android API11以前版本的XmlPullParser.getInputEncoding()的不同行爲

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文件,它們具有完全相同的頭文件:<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>爲什麼getInputEncoding()在API11 +上返回null?

附加發現:

我們已經發現,有這樣的一種方法來使用FileInputStream正確檢測API11 +設備文件的編碼,而不是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。所以現在我可以在代碼中插入一個叉子上預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?

回答

4

一些更多的嘗試和錯誤後收到主叫.next() intially,我終於設法弄清楚發生了什麼事情。所以,儘管the documentation說:

歷史Android已經有這個接口的兩個實現:通過XmlPullParserFactory.newPullParser KXmlParser()。ExpatPullParser,通過Xml.newPullParser()。

任何一個選項都可以。本節中的示例使用ExpatPullParser,通過Xml.newPullParser()。

現實情況是,在較舊的API上,如2.3.3 Xml.newPullParser()返回ExpatPullParser對象。在冰淇淋三明治上,它返回KXmlParser對象。正如我們可以從this blog post看到,Android開發者知道這一點,因爲2011年12月:

在Ice Cream Sandwich的,我們改變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」。

0

FileReader和其他閱讀器不檢測編碼。他們只是巧妙地使用平臺默認編碼,它可以是UTF-8。它與文件的實際編碼無關。

只有閱讀足夠的內容才能看到encoding屬性,否則無法檢測到XML文件編碼。

getInputEncoding() documentation

如果inputEncoding是空和解析器支持的編碼 檢測功能,它必須返回檢測到編碼

和:

如果setInput設置(Reader)被調用,返回null。

因此,似乎前11不支持通過使用setInput(is, null)啓用檢測。我不知道如何在使用setInput(reader)時得到"UTF-8",因爲文檔說它應該返回null

然後:

到明年第一個電話,如果XML聲明存在這種方法 將返回了編碼聲明之後。

所以在前期11,你可以嘗試調用.getInputEncoding

+0

我試着按照你的指示,但是在API11前調用.next()並沒有幫助,getInputEncoding()一直返回'null'。 –

+0

請看看我對這個問題的回答。你調用'.next()'是正確的,但還有第二部分:我應該使用'XmlPullParserFactory.newPullParser()'而不是'Xml.newPullParser()'。當然,使用'FileInputStream'而不是'FileReader'。 –

相關問題