Android SaxParser 和 OutOfMemory 异常

标签 android android-xml android-parser

我目前正在从事一个创建 TCP 套接字并监听服务器以获取传入 xml 的项目。 xml 有时相当大,大约 1-3 mb。 xml 不断来自套接字,我需要在它到来时对其进行解析。 我尝试了许多解析器,如 DomParser、XMLPullParser 和 SaxParser。萨克斯似乎是最快的,所以我继续了。但是现在我有时会遇到 OutOfMemory 异常。

我在这篇文章中读到我们应该以 block 的形式向解析器发送数据。

How to parse huge xml data from webservice in Android application?

谁能告诉我这是怎么做到的。我当前的代码是这样的

InputSource xmlInputSource  =   new InputSource(new StringReader(response));
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();
}catch(ParserConfigurationException e){
    e.printStackTrace();
}catch (IOException e){
    e.printStackTrace();
    e.toString();
}

其中 response 是我从套接字接收到的字符串。

是否应该查看 VTD-XML 等其他解析器?或者有没有办法让 Sax 高效工作?

顺便说一句:每当一个新字符串到达​​要解析的套接字时,我都会打开一个新线程来解析该字符串。

This is my handler code    

public class ParseHandler extends DefaultHandler {
    private Website     mWebsite;
    private Visitor     mVisitor;
    private VisitorInfo mVisitorInfo;
    private boolean     isVisit;
    private boolean     isVisitor;
    private AppContext  appContext;

    public ParseHandler(int index,AppContext context){
        appContext          =   context;
        mWebsite            =   appContext.getSiteListArray().get(index);
    }

    @Override
    public void startDocument() throws SAXException {
        super.startDocument();        
    }

    @Override
    public void startElement(String namespaceURI, String localName,String qName, Attributes atts) 
            throws SAXException {
        if(localName.equals("visit")) {
            isVisit = true;            
        } else if(localName.equals("visitor") && isVisit) {
            isVisitor  = true; 
            mVisitor = new Visitor();
            mVisitor.mDisplayName = "Visitor - #"+atts.getValue("id");
            mVisitor.mVisitorId   = atts.getValue("id");
            mVisitor.mStatus      = atts.getValue("idle");
        } else if(localName.equals("info") && isVisitor){
            mVisitorInfo = mVisitor.new VisitorInfo();
            mVisitorInfo.mBrowser     = atts.getValue("browser");
            mVisitorInfo.mBrowserName = atts.getValue("browser").replace("+", " ");
            mVisitorInfo.mCity        = atts.getValue("city").replace("+", " ");
            mVisitorInfo.mCountry     = atts.getValue("country");
            mVisitorInfo.mCountryName = atts.getValue("country");
            mVisitorInfo.mDomain      = atts.getValue("domain");
            mVisitorInfo.mIp          = atts.getValue("ip");
            mVisitorInfo.mLanguage    = atts.getValue("language");
            mVisitorInfo.mLatitude    = atts.getValue("lat");
            mVisitorInfo.mLongitude   = atts.getValue("long");
            mVisitorInfo.mOrg         = atts.getValue("org").replace("+", " ");
            mVisitorInfo.mOs          = atts.getValue("os");
            mVisitorInfo.mOsName      = atts.getValue("os").replace("+", " ");
            mVisitorInfo.mRegion      = atts.getValue("region").replace("+", " ");
            mVisitorInfo.mScreen      = atts.getValue("screen");
        }
    }   

    @Override
    public void characters(char ch[], int start, int length) {
    }

    @Override
    public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
        if(localName.equals("visit")) {
            isVisit  = false;
        } else if(localName.equals("visitor")) {
            isVisitor = false;
            if(mVisitor == null){
                Log.e("mVisitor","mVisitor");
            } else if(mVisitor.mVisitorId == null){
                Log.e("mVisitor.mVisitorId","mVisitor.mVisitorId");   
            }
            mWebsite.mVisitors.put(mVisitor.mVisitorId, mVisitor);
        } else if(localName.equals("info")  && isVisitor) {
            mVisitor.mVisitorInfo = mVisitorInfo;
        }
    }

    @Override
    public void endDocument() throws SAXException {

    }
}

**

编辑:经过深思熟虑..

**

经过进一步调查,我发现我的解析并没有导致异常。 每次我从套接字接收到一个流时,我将它存储在一个字符串中,并且我一直附加它直到我们在流中得到“\n”。 “\n”用于表示 xml block 的结尾。 字符串导致内存异常。我尝试了 StringBuilder 但这也导致了同样的问题。我不知道为什么会这样。

现在我尝试直接发送输入流进行解析,但末尾的“\n”会导致解析异常。有什么我们可以设置的,以便解析器忽略“\n”吗?

最佳答案

似乎您正在将整个 xml 文件传递​​给解析器,因此每当文件太大时,您都会遇到 outOfMemory 异常。

您应该尝试以 block 的形式从套接字中读取输出,并将其提供给解析器。因此,您将在循环内执行 xr.parse()。

关于Android SaxParser 和 OutOfMemory 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7048892/

相关文章:

安卓 : Error in parsing JSON array using GSON library

android - 无法在 Android Studio 2.2 中创建发布 apk

android - Xamarin.Android 应用程序中的 XML 和 AXML 有什么区别?

安卓用户界面元素

android - 像 html 一样显示 android TextViews 会 float div

android - Robolectric:Android 中的 SAXParser 与 Java 中的 SAXParser (robolectric):localname 与 qname 的差异

android - android 中的 XML 解析器

java - 应用程序在进入异常时终止

android - 如何在 videoview android 中播放来自 youtube 源的视频

Android 文字颜色不起作用