0

I'm working on an app that prints the values that are on a table on my local MySQL database. Basically the app uses a php file (which is stored on the web server) that defines the Select query and returns the result into a Json array. The array is then used and printed into the app.

I get that exception on the Logcat where apparently my json array is null. I have already read What is a NullPointerException, and how do I fix it? but I could not find a solution to my problem.

import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends AppCompatActivity {

    ListView listView;

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

        listView = (ListView) findViewById(R.id.listView);
        downloadJSON("http://127.0.0.1/api/stock_service.php");
    }


    private void downloadJSON(final String urlWebService) {

        class DownloadJSON extends AsyncTask<Void, Void, String> {

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
            }


            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                //Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show();
                try {
                    loadIntoListView(s);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            @Override
            protected String doInBackground(Void... voids) {
                try {
                    URL url = new URL(urlWebService);
                    HttpURLConnection con = (HttpURLConnection) url.openConnection();
                    StringBuilder sb = new StringBuilder();
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
                    String json;
                    while ((json = bufferedReader.readLine()) != null) {
                        sb.append(json + "\n");
                    }
                    return sb.toString().trim();
                } catch (Exception e) {
                    return null;
                }
            }
        }
        DownloadJSON getJSON = new DownloadJSON();
        getJSON.execute();
    }

    private void loadIntoListView(String json) throws JSONException {
        JSONArray jsonArray = new JSONArray(json);
        String[] stocks = new String[jsonArray.length()];
        for (int i = 0; i < jsonArray.length(); i++) {
            JSONObject obj = jsonArray.getJSONObject(i);
            stocks[i] = obj.getString("name") + " " + obj.getString("price");
        }
        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, stocks);
        listView.setAdapter(arrayAdapter);
    }
}

This is the Logcat. At line 77 I have: JSONArray jsonArray = new JSONArray(json);.

     java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
        at org.json.JSONTokener.nextCleanInternal(JSONTokener.java:121)
        at org.json.JSONTokener.nextValue(JSONTokener.java:98)
        at org.json.JSONArray.<init>(JSONArray.java:94)
        at org.json.JSONArray.<init>(JSONArray.java:110)
        at com.example.testdb.MainActivity.loadIntoListView(MainActivity.java:77)
        at com.example.testdb.MainActivity.access$000(MainActivity.java:20)
        at com.example.testdb.MainActivity$1DownloadJSON.onPostExecute(MainActivity.java:49)
        at com.example.testdb.MainActivity$1DownloadJSON.onPostExecute(MainActivity.java:36)
        at android.os.AsyncTask.finish(AsyncTask.java:771)
        at android.os.AsyncTask.access$900(AsyncTask.java:199)
        at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7523)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
Luca
  • 21
  • 7
  • Aside I wouldn't be using `AsyncTask` as its deprecated and if you want to make a http request to get a `JSONArray` save yourself the headache and use a library like Android Volley. Please see this answer for more https://stackoverflow.com/a/65000933/1133011 – David Kroukamp Nov 29 '20 at 11:47
  • @StephenC What do you think it is? Null parameter – Luca Nov 29 '20 at 13:21
  • I mean its pretty obvious mate, the String `json` must be null? Put a breakpoint on that line that you get the error and debug and see what the value of `json` is. Also I would heed my warning on the `AsyncTask` and manually making your own requests. But what do I know – David Kroukamp Nov 29 '20 at 13:28
  • @DavidKroukamp Yeah I was alerady trying to change AsyncTask – Luca Nov 29 '20 at 13:32
  • Great that's a good start. And if you don't know how to debug please do read this its life changing https://developer.android.com/studio/debug and for NullPointerExceptions this is the cure. You put a breakpoint on the line giving you the error and debug hover over variables and you will see which ones are null... then you can trace back and attempt to find your problem. – David Kroukamp Nov 29 '20 at 13:34
  • @DavidKroukamp I'll work on that thanks. – Luca Nov 29 '20 at 13:42
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/225278/discussion-between-luca-and-david-kroukamp). – Luca Nov 29 '20 at 14:19

1 Answers1

1

The NPE is occurring within the new JSONArray(json) call because json is null. That is the easy part. The harder part is where the null is coming from.

The call stack says that loadIntoListView is called from onPostExecute, but it is just passing through the s parameter it was called with. Keep looking.

So what is this code actually doing? Well it is calling a remote service and then trying to process the JSON that it returns. Where does that happen?

The doInBackground is making a remote service call using HTTPURLConnection etc. So lets have a look at that. As you can see, if the service call succeeds it reads data from the connection output stream and turns it all into a String and returns it.

But what if the service call fails?

            } catch (Exception e) {
                return null;
            }

Ouch!

That's where your null is coming from.

That exception handling code is wrong in a number of ways:

  1. You shouldn't catch Exception. Only catch the specific exceptions that you are expecting. In most cases, any unexpected exceptions should be allowed to propagate.

  2. When you handle an exception, you should (typically) report or log or something the exception message and/or the stacktrace. If you don't you are throwing away information that may be useful to someone; e.g. to you, when you are trying to diagnose bugs like this one.

  3. You shouldn't (normally) return null from a method that is supposed to return data. Returning null is a poor way to indicate something hasn't worked.

    Why? Because it is liable to trigger NPE's if the null gets passed to some other code that doesn't expect a null. As has happened here.

  4. If you do return null here, the code elsewhere that populates the view from the JSON needs to deal with possibility of a null instead of valid JSON.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Damn I totally overlooked that ```return null```. Thanks. Btw since it always enters the Catch clause it means that the remote service call using httpurlconnection fails right? – Luca Nov 29 '20 at 13:57
  • Probably. You need to confirm that by looking at the stacktrace for the exception that you caught there. – Stephen C Nov 29 '20 at 13:59