我正在开发一个 android 客户端,该客户端通过 TCP 套接字从我的 java 服务器读取持续的 xml 数据流。服务器发送一个 '\n' 字符作为连续响应之间的分隔符。下面给出了一个模型实现..
<response1>
<datas>
<data>
.....
.....
</data>
<data>
.....
.....
</data>
........
........
</datas>
</response1>\n <--- \n acts as delimiter ---/>
<response2>
<datas>
<data>
.....
.....
</data>
<data>
.....
.....
</data>
........
........
</datas>
</response2>\n
好吧,我希望现在结构清晰。此响应是从服务器 zlib 压缩传输的。所以我必须首先膨胀我从服务器读取的任何内容,使用分隔符和解析分开响应。我正在使用 SAX 解析我的 XML
现在我的主要问题是来自服务器的 xml 响应可能非常大(可以在 3 到 4 MB 的范围内)。所以
要基于分隔符 (\n) 分隔响应,我必须使用 stringBuilder来存储响应块,因为它从套接字读取,并且在某些手机上 StringBuilder 无法存储兆字节范围内的字符串。它给出了OutOfMemory异常,并且从这样的线程中我了解到保留大字符串(即使是临时的)并不是一个好主意。
接下来,我尝试将 inflatorReadStream(它反过来从套接字输入流中获取数据)作为 SAX 解析器的输入流(无需自己分离 xml 并依赖 SAX 基于标签查找文档结尾的能力)。这一次成功解析了一个响应,但随后在找到 '\n' 分隔符时,SAX 会抛出ExpatParserParseException,说 junk after document element。
- 在捕捉到ExpatParserParseException之后,我尝试再次读取,但是在抛出异常 SAX Parser 后关闭了流,所以当我再次尝试读取/解析时,它给出IOException说输入流已关闭。
下面给出了我所做的代码片段(为了清楚起见,删除了所有不相关的 try catch 块)。
private Socket clientSocket = null;
DataInputStream readStream = null;
DataOutputStream writeStream = null;
private StringBuilder incompleteResponse = null;
private AppContext context = null;
public boolean connectToHost(String ipAddress, int port,AppContext myContext){
context = myContext;
website = site;
InetAddress serverAddr = null;
serverAddr = InetAddress.getByName(website.mIpAddress);
clientSocket = new Socket(serverAddr, port);
//If connected create a read and write Stream objects..
readStream = new DataInputStream(new InflaterInputStream(clientSocket.getInputStream()));
writeStream = new DataOutputStream(clientSocket.getOutputStream());
Thread readThread = new Thread(){
@Override
public void run(){
ReadFromSocket();
}
};
readThread.start();
return true;
}
public void ReadFromSocket(){
while(true){
InputSource xmlInputSource = new InputSource(readStream);
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = null;
XMLReader xr = null;
try{
sp = spf.newSAXParser();
xr = sp.getXMLReader();
ParseHandler xmlHandler = new ParseHandler(context.getSiteListArray().indexOf(website), context);
xr.setContentHandler(xmlHandler);
xr.parse(xmlInputSource);
// postSuccessfullParsingNotification();
}catch(SAXException e){
e.printStackTrace();
postSuccessfullParsingNotification();
}catch(ParserConfigurationException e){
e.printStackTrace();
postSocketDisconnectionBroadcast();
break;
}catch (IOException e){
postSocketDisconnectionBroadcast();
e.printStackTrace();
e.toString();
break;
}catch (Exception e){
postSocketDisconnectionBroadcast();
e.printStackTrace();
break;
}
}
}
现在我的问题是
- 有没有办法让 SAX Parser 在 xml 响应之后忽略垃圾字符,而不是抛出异常并关闭流..
- 如果没有,有什么方法可以避免 stringBuilder 出现内存不足错误。坦率地说,我对此并不例外。任何解决方法?