目前一个Android应用,要把对象生成XML,目前用的是StringBuffer来append完成的,但是数据量过大的时候就报OutOfMemory,原因就是AbstractStringBuilder的enlargeBuffer方法在容量不够的时候申请的是按额外增加两倍的容量来做的
Java代码
private void enlargeBuffer(int min) {
int newSize = ((value.length >> 1) + value.length) + 2;
char[] newData = new char[min > newSize ? min : newSize];
System.arraycopy(value, 0, newData, 0, count);
value = newData;
shared = false;
}
private void enlargeBuffer(int min) {
int newSize = ((value.length >> 1) + value.length) + 2;
char[] newData = new char[min > newSize ? min : newSize];
System.arraycopy(value, 0, newData, 0, count);
value = newData;
shared = false;
}
这样就超出了,目前是做的是预估算下数据的容量,然后直接先分配好,再来append,这样可以解决一点问题,但不能根本的解决问题,数据量再增多或者有估算不准还是会OutOfMemory
看了有些人的做法是分块来组装的,比如一个大的XML文件分很多块,它就每块每块的来拼接,最后再组装成一个大的
目前我这里是有个XMLNode对象,里面有XMLNode parent,List<XMLNode> children,int token,XMLNode自己有个toXMLString方法,拼接都在这里面
整个过程就是把POJO转成XMLNode,再用toXMLString
还有人提议先把XMLNode转换成临时文件,越过AbstractStringBuilder这里面的方法
我写了点也写不下去了,在XMLNode的toXML会涉及到递归,对于文件递归生成一个文件再添加到原来的文件这里搞不定啊
大家有没有什么高招,最好不要替换现有的解析XML程序,这个也不知道谁写的,谢谢大家
更新:为了不让这个帖子成为太监贴,还是把我解决的思路提出来
总体上我觉得目前这样做是不大妥当的,最好的情况数据应该来分批次发送,或者用WBXML,或者压缩后发送,但是目前服务器不这样支持,我也没有办法
我解决的方式还是利用文件来做的,也就是先把Java对象转化为XML文件,用了org.kxml2.io.KXmlSerializer库,把原来那个别人写的Formatter替换掉了,最后再用HttpClient发送请求到服务器端,虽然速度有点慢,但是不至于程序直接就Crash掉
以前发送小的XML文件就用的HttpURLConnection,它是把数据都写入内存的,所以有时候就报OOM了,代码如下
Java代码
ByteArrayOutputStream baos = new ByteArrayOutputStream();
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestProperty("Charset", "UTF-8");
conn.addRequestProperty("Content-Type",
"application/vnd.syncml+xml;charset=UTF-8");
conn.addRequestProperty("cache-control", "no-store");
conn.addRequestProperty("accept",
"application/vnd.syncml+wbxml, application/vnd.syncml+xml;");
conn.addRequestProperty("accept-charset", "UTF-8");
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
OutputStream os = conn.getOutputStream();
os.write(baos.toByteArray());
os.close();
baos.close();
conn.connect();
int statusCode = conn.getResponseCode();
if (HttpURLConnection.HTTP_OK == statusCode) {
InputStream is = conn.getInputStream();
} else {
// DO XXOO HERE
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestProperty("Charset", "UTF-8");
conn.addRequestProperty("Content-Type",
"application/vnd.syncml+xml;charset=UTF-8");
conn.addRequestProperty("cache-control", "no-store");
conn.addRequestProperty("accept",
"application/vnd.syncml+wbxml, application/vnd.syncml+xml;");
conn.addRequestProperty("accept-charset", "UTF-8");
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
OutputStream os = conn.getOutputStream();
os.write(baos.toByteArray());
os.close();
baos.close();
conn.connect();
int statusCode = conn.getResponseCode();
if (HttpURLConnection.HTTP_OK == statusCode) {
InputStream is = conn.getInputStream();
} else {
// DO XXOO HERE
}
现在换成了
Java代码
HttpPost postRequest = new HttpPost(url);
File tmpFile = new File("/data/data/tmp.xml");
FileEntity entity = new FileEntity(tmpFile, "application/vnd.syncml+xml;charset=UTF-8");
entity.setContentEncoding("UTF-8");
postRequest.setEntity(entity);
HttpResponse response = httpClient.execute(postRequest);
InputStream content = response.getEntity().getContent();
int statusCode = response.getStatusLine().getStatusCode();
if (200 == statusCode) {
} else {
// DO XXOO HERE
}
HttpPost postRequest = new HttpPost(url);
File tmpFile = new File("/data/data/tmp.xml");
FileEntity entity = new FileEntity(tmpFile, "application/vnd.syncml+xml;charset=UTF-8");
entity.setContentEncoding("UTF-8");
postRequest.setEntity(entity);
HttpResponse response = httpClient.execute(postRequest);
InputStream content = response.getEntity().getContent();
int statusCode = response.getStatusLine().getStatusCode();
if (200 == statusCode) {
} else {
// DO XXOO HERE
}
|