2

Why do I always get a NullPointerException when I run my application? Every time I start my genymotion emulator and then run the app the first time, it crashes, but the 2nd time I run my app in works smoothly. I don't know why it happens everytime on the first run.

Here is my Splash screen which retrieves the JSON object from the RetrieveGamesBGTask:

public class Splash extends Activity {
     RetrieveGamesBGTask retrieveGamesBGTask;
    String json_string;

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

        Thread thread = new Thread(){
            @Override
            public void run() {
                try {
                    retrieveGamesBGTask = new RetrieveGamesBGTask();
                    retrieveGamesBGTask.execute();
                    sleep(3000);
                    Intent intent = new Intent(getApplication(), Games.class);
                    intent.putExtra("json_data", json_string);
                    intent.putExtra("json_data", retrieveGamesBGTask.getResult());
                    startActivity(intent);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        thread.start();

Here is the next application where it crashes every time on the first run:

 retrieveGamesBGTask = new RetrieveGamesBGTask();
        retrieveGamesBGTask.execute();

  Intent intent = this.getIntent();

        if (intent != null) {
            json_string = intent.getStringExtra("json_data");
        }


        try {
            if (jsonObject == null) {
                jsonObject = new JSONObject(json_string);
                jsonArray = jsonObject.getJSONArray("server_response");
                int count = 0;
                String teamone, teamonepts, teamtwo, teamtwopts, s_name, s_gender;

                while (count < jsonArray.length()) {
                    JSONObject JO = jsonArray.getJSONObject(count);
                    teamone = JO.getString("teamone");
                    teamonepts = JO.getString("teamonepts");
                    teamtwo = JO.getString("teamtwo");
                    teamtwopts = JO.getString("teamtwopts");
                    s_name = JO.getString("s_name");
                    s_gender = JO.getString("s_gender");
                    Downloader downloader = new Downloader(teamone, teamonepts, teamtwo, teamtwopts, s_name, s_gender);
                    gamesAdapter.add(downloader);

                    count++;
                }
            } else {
                Toast.makeText(this, "JSON is null", Toast.LENGTH_LONG).show();
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

Here is my RetrieveGamesBGTask

class RetrieveGamesBGTask extends AsyncTask<Void, Void, String> {
    String json_result, json_string;

    @Override
    protected void onPreExecute() {


    }

    @Override
    protected String doInBackground(Void... params) {
        try {
            URL url = new URL(Config.URL_GAMES);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            InputStream inputstream = httpURLConnection.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputstream));
            StringBuilder stringBuilder = new StringBuilder();
            while ((json_string = bufferedReader.readLine()) != null) {
                stringBuilder.append(json_string + "\n");
            }

            bufferedReader.close();
            inputstream.close();
            httpURLConnection.disconnect();
            return stringBuilder.toString().trim();

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d("haha", "hehe");
        json_result = result;
    }

    public String getResult() {
        return json_result;
    }

Here is my logcat:

FATAL EXCEPTION: main 
Process: com.example.aaa.bbb, PID: 5680
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.aaa.bbb/com.example.aaa.bbb.Games}: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
4
  • Do you get any data in json_string? Commented Dec 12, 2016 at 12:46
  • can you post RetrieveGamesBGTask class? what happens after you get a result ? Commented Dec 12, 2016 at 12:46
  • added the class sir. It goes to the next class which is the games class. Where teams and scores are posted. It works on the 2nd time i run the app Commented Dec 12, 2016 at 12:50
  • Why are you putting the thread to sleep for 3 seconds? I would use Volley or Retrofit 2.0. The latter is really fast. Commented Dec 12, 2016 at 15:01

3 Answers 3

7

There's a couple of things you could do better here. But your main problem is that you are doing async tasks(backgroundtask) and not handling a proper callback.

What happens in the following:

  1. Starting of the async task.
  2. You sleep for 3 seconds (Which is probably to try to make the async finish before the code continues.)
  3. The Async task might not have finish have finished in the 3 seconds.
  4. Your try to parse the JSON that has not been received yet.
  5. This throws a nullpointer.

Now while crashing the async task still runs and finishes. I'm not sure if you save this JSON and then it becomes readable while completing and becomes available the second time, or that the second time the task might finish within 3 seconds.

What you should do

  1. Starting of the async task.
  2. Do Not let the thread sleep.
  3. In the async task onPostExecute have a callback to your main thread.
  4. Have the callback return the JSON obtained from the task.
  5. Now parse the JSON you will have, if the call itself did succeed.

To achieve this look here https://developer.android.com/training/best-background.html

It should provide enough information to get this piece of code stable.

Sign up to request clarification or add additional context in comments.

3 Comments

What if i let it sleep for more that 3 sec? is it possible that way sir?
It's not a good practice to just wait for a magic x number of seconds. You just can not know how long it's going to take for the async task to finish. That's what the onPostExecute is for. It let's you know when the task is actually done and then you can be sure the data is available. While in theory you could do so, I really do not recommend doing this.
Great explanation, osoda it is bad practice to use sleep Still if you want to wait till async task executes you can write some thing like this String result= new myAsyncTask().execute().get(); but the Ui will freeze until you get the result ,its not recommended
1

Another way you can place intent inside your post execute. in your Activity's onCreate method

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

    new RetrieveGamesBGTask(Splash.this).execute();

}

now in your RetrieveGamesBGTask's onPostExecute method

@Override
protected void onPostExecute(String result) {
    Log.d("haha", "hehe");
    json_result = result;
    Intent intent = new Intent(context, Games.class);
                intent.putExtra("json_data", json_string);
                intent.putExtra("json_data",json_result);
                context.startActivity(intent);
}

Comments

-1

Well the error is quite clear:

Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference

So somewhere you call length on a not initialized string. This is not in the code you posted. (only jsonArray.length())

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.