【问题标题】:Android SaxParser and OutOfMemory ExceptionAndroid SaxParser 和 OutOfMemory 异常
【发布时间】:2011-08-13 05:58:07
【问题描述】:

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

我在这篇文章中读到,我们应该以块的形式向解析器提供数据。

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?或者有没有办法让萨克斯高效工作?

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

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 块的结束。 字符串导致内存异常。我尝试了 StringBuilder 但这也导致了同样的问题。我不知道为什么会这样。

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

【问题讨论】:

  • 你能发布你的处理程序代码吗?
  • @JRL 我已经更新了我的问题

标签: android android-xml android-parser


【解决方案1】:

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

您应该尝试以块的形式从套接字读取输出,并将其提供给解析器。所以你会在一个循环中执行 xr.parse()。

【讨论】:

  • 经过进一步调查,我发现我的解析不会导致异常。每次我从套接字接收到一个流时,我都会将它存储在一个字符串中,并且我会一直附加它,直到我们在流中得到“\n”。 "\n" 用于表示 xml 块的结束。该字符串导致内存异常。我尝试了 StringBuilder 但这也导致了同样的问题。我不知道为什么会这样。现在我尝试了你的方法,解析很好,但是 "\n" 会导致解析异常。我们可以设置什么让解析器忽略“\n”吗?
  • 我不确定这是很久以前的事了,但我相信解析器中有一些选项可以告诉它忽略不重要的空格,例如在行和换行符的开头格式化制表符和空格
  • 在此处查看文档以获取想法 ignorableWhitespace download.oracle.com/javase/1.4.2/docs/api/org/xml/sax/…, int, int)
【解决方案2】:

另一个帖子是关于我的问题的,那里的答案是我的问题的解决方案。

这是为遇到此问题的任何人提供的解决方案。

Reading big chunk of xml data from socket and parse on the fly

【讨论】:

  • 好的,不太明白你的意思 \n :-)
  • "\n" 用于区分 xml 块的分隔符。 \n
猜你喜欢
  • 1970-01-01
  • 2013-05-27
  • 2011-06-23
  • 2017-05-04
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 2014-04-05
相关资源
最近更新 更多