简体   繁体   中英

Getting a NullPointerException while trying to parse XML file using DOM

I've been struggling with this for about 3 days already and finally I decided to take a risk and ask you guys. The problem is, that I get NullPointerException as you already got from the title. With a debugger I found the source of my problems, so I know exactly what causes that nullpointer: its the variable "doc" of type Document, which you can find in the code below. Sorry for too many words, here is the code

This is the code of my class DomXmlParser

public class DomXmlParser {
    Document doc;
    String urlLink;
    InputStream is;

    public DomXmlParser(String url){
        this.urlLink = url;
    }

    public Document getDoc(){
        return doc;
    }
    public void parseXML(InputStream is) {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            doc = builder.parse(is);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void getXML(){
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    URL url = new URL(urlLink);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("POST");
                    conn.setReadTimeout(15000);
                    conn.setConnectTimeout(15000);
                    conn.setDoInput(true);
                    conn.connect();
                    is = conn.getInputStream();
                    Log.d("InputStreamContents", is.toString());
                    parseXML(is);
                    is.close();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        });
        thread.start();
    }
}

So, in MainActivity I call getXml() method and then getDoc().

public void parseDom(){
    DomXmlParser parser = new DomXmlParser(xmlUrl);
    parser.getXML();
    doc = parser.getDoc();
    NodeList list = doc.getElementsByTagName("item");
    for (int i = 0; i < list.getLength(); i++){
        Node item = list.item(i);
        if (item.getNodeType()==Node.ELEMENT_NODE){
            Element data = (Element) item;
            NodeList dataList = data.getChildNodes();
            for (int j = 0; j < dataList.getLength(); i++){
                Node p = dataList.item(j);
                if (p.getNodeType()==Node.ELEMENT_NODE){
                    Element title = (Element) p;
                    Element description = (Element) p;
                    FeedItem fi = new FeedItem();
                    fi.setName(title.getTextContent());
                    fi.setStatus(description.getTextContent());
                    feedItems.add(fi);
                }
            }
        }
    }
}

I debugged my application, and it looks like the getDoc() method returns null. Also it says that the line

NodeList list = doc.getElementsByTagName("item");

returns null. So, the Document doc variable of the DomXmlParser class is null. I know for sure, that InputStream is not null, also everything worked fine when I tried to parse XML via XmlPullParser, so either XML file or link are OK. Hope you help me guys cause neither I, nor google know what to do.

UPDATE: As it was suggested in the answer below, I removed the Thread, and just created a class that exnteds AsyncTask in MainActivity, so now I don't have that NullPointer, but I have the other problem: Out of memory on a 144-byte allocation. And I have no idea what to do with it.

Logs

10-29 00:17:13.139    3258-3258/com.motoharu.cleaningapp E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.NullPointerException
            at com.motoharu.cleaningapp.HomeFragment.parseDom(HomeFragment.java:151)
            at com.motoharu.cleaningapp.HomeFragment.initControls(HomeFragment.java:78)
            at com.motoharu.cleaningapp.HomeFragment.onStart(HomeFragment.java:70)
            at android.support.v4.app.Fragment.performStart(Fragment.java:1528)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:972)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1121)
            at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
            at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1484)
            at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:482)
            at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
            at android.support.v4.view.ViewPager.populate(ViewPager.java:1073)
            at android.support.v4.view.ViewPager.populate(ViewPager.java:919)
            at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1441)
            at android.view.View.measure(View.java:16030)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5012)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:314)
            at android.view.View.measure(View.java:16030)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5012)
            at com.android.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:302)
            at android.view.View.measure(View.java:16030)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5012)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:314)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2196)
            at android.view.View.measure(View.java:16030)
            at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1915)
            at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1109)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1290)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1009)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5508)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
            at android.view.Choreographer.doCallbacks(Choreographer.java:562)
            at android.view.Choreographer.doFrame(Choreographer.java:532)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
            at android.os.Handler.handleCallback(Handler.java:730)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:213)
            at android.app.ActivityThread.main(ActivityThread.java:5225)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:741)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
            at dalvik.system.NativeStart.main(Native Method)

The problem is because getXML is spawning a new thread that constructs the Document object referenced by doc . So after calling parser.getXML() , the code tries to access the doc variable using the getDoc() method, but this variable is still not initialized by that thread.

The solution is to wait for the thread to finish. This can simply be done using a join . For example, you can create the new Thread when calling the getXML method, instead of creating it inside the method itself.

public void getXML(){       
    try {
       URL url = new URL(urlLink);
       HttpURLConnection conn = (HttpURLConnection) url.openConnection();
       conn.setRequestMethod("POST");
       conn.setReadTimeout(15000);
       conn.setConnectTimeout(15000);
       conn.setDoInput(true);
       conn.connect();
       is = conn.getInputStream();
       Log.d("InputStreamContents", is.toString());
       parseXML(is);
       is.close();
   }catch(Exception e){
       e.printStackTrace();
   }
}

In parseDom

final DomXmlParser parser = new DomXmlParser(xmlUrl);

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        parser.getXML();
    }
});
thread.start();
try {
    thread.join();  // wait until above thread finishes
} catch (InterruptedException e) {
    // handle the exception here
}
doc = parser.getDoc();

Well, some kind of answer. As far as the only answer didn't solved my problem I continued googling and found an information saying, that it's better to use not DOM, but SAX parser to parse RSS feed, so I did so. But, eventualy, I faced the same NullPointer problem and I didn't know why. And everything was because that data, which I was getting inside new thread didn't interract with the data outside the Thread, as Sir manouti said. So, his answer solved my problem but with SAX parser this time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM