SimranTea SimranTea - 7 months ago 153
Java Question

Android Studio - Parsing with jsoup throws error (java.lang.NullPointerException)

I am trying to data_mine a table from a website, store it into an

ArrayList<String>
and view it on a
ListView
layout. Every time I run the program I get this error.

04-29 23:52:57.122 20095-20095/com.example.user.datamining E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.project.datamining, PID: 20095
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.user.datamining/com.example.user.DataMining}: java.lang.NullPointerException: Attempt to invoke virtual method 'org.jsoup.select.Elements org.jsoup.nodes.Document.select(java.lang.String)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2521)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2595)
at android.app.ActivityThread.access$800(ActivityThread.java:178)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1470)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5631)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'org.jsoup.select.Elements org.jsoup.nodes.Document.select(java.lang.String)' on a null object reference


This is my code:

package com.example.user.datamining;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.util.ArrayList;

public class DataMining extends AppCompatActivity {
Document doc;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_data_mining);

Thread downloadThread = new Thread() {
public void run() {

try {
doc = Jsoup.connect("http://thewebsite.html").get();
} catch (IOException e) {
e.printStackTrace();
}
}
};
downloadThread.start();

ArrayList<String> list = new ArrayList();
Elements table = doc.select("table");
Elements rows = table.select("tr");

for (int i = 0; i < rows.size(); i++) {
org.jsoup.nodes.Element row = rows.get(i);
Elements cols = row.select("td");

list.add(cols.get(i).text());


ArrayAdapter<String> adapter = new ArrayAdapter(this, R.layout.datalayout, list);
ListView view = (ListView) findViewById(R.id.dataListView);
view.setAdapter(adapter);
}

}
}

Answer

You're starting a separate thread to perform the download, and initialize doc. This thread runs asynchronously, so doc is still null when you call select() on it right after starting the thread.

Move the parsing code to after the download in the thread's run() method, and use the Activity's runOnUiThread() method after the parse to set the ListView's Adapter, since you can't touch Views directly from that download thread.

private Document doc;
private ArrayList<String> list = new ArrayList<>();

@Override
protected void onCreat(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_data_mining);

    Thread downloadThread = new Thread() {
        public void run() {
            try {
                doc = Jsoup.connect("http://thewebsite.html").get();

                Elements table = doc.select("table"); 
                Elements rows = table.select("tr");

                for (int i = 0; i < rows.size(); i++) { 
                    org.jsoup.nodes.Element row =  rows.get(i);
                    Elements cols = row.select("td");

                    list.add(cols.get(i).text());
                }

                runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            setListAdapter();
                        }
                    }
                );
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    };
    downloadThread.start();
}

private void setListAdapter() {
    ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.datalayout, list);
    ListView view = (ListView) findViewById(R.id.dataListView);
    view.setAdapter(adapter);
}