私は、TCPソケットを介してJavaサーバーからxmlデータの継続ストリームを読み取るAndroidクライアントで作業しています。サーバーは、連続する応答間の区切り文字として「\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の機能に依存することはありません)。今回は1つの応答が正常に解析されますが、'\ n'区切り文字を見つけると、SAXはドキュメント要素の後にジャンクと言って ExpatParserParseExceptionをスローします。
- そのExpatParserParseExceptionをキャッチした後、もう一度読み取ろうとしましたが、例外をスローした後、SAXパーサーはストリームを閉じるため、再度読み取り/解析しようとすると、入力ストリームが閉じていることを示す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パーサーがxml応答後にジャンク文字を無視し、例外をスローしてストリームを閉じないようにする方法はありますか?
- そうでない場合は、stringBuilderのメモリ不足エラーを回避する方法はありません。率直に言って、私はこれについて肯定的な答えを除いていません。回避策はありますか?