Search code examples
javaandroidandroid-studioandroid-asynctask

AsyncTask keeps crashing demo app running on Android emulator


I'm currently learning Android app development by working through a book and I'm currently struggling with something that seems to be fairly simple on the face of it. The interface consists of a button and a text view. The idea of the exercise is to demonstrate how using a separate thread is useful when performing time consuming tasks.

I've tried debugging and the values array of the onProgressUpdate method does contain the value passed into it and the crash seems to always happen when trying to set the text for myTextView. I'd be grateful for any help.

Code:

package com.ebookfrenzy.asyncdemo;

import androidx.appcompat.app.AppCompatActivity;
import android.os.AsyncTask;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private TextView myTextView;
    private String tag = "Test";

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

    public void buttonClick(View view) {
        AsyncTask task = new MyTask().execute();
    }

    private class MyTask extends AsyncTask<String,Integer,String> {
        @Override
        protected void onPreExecute() {

        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            Log.i(tag,"publish: " + Integer.toString(values[0]));
            myTextView.setText("Counter = " + values[0]);
        }

        @Override
        protected void onPostExecute(String result) {
            myTextView.setText(result);
        }

        @Override
        protected String doInBackground(String... strings) {
            int i = 0;
            while (i <= 20) {
                Log.i(tag,"before publish: " + Integer.toString(i));
                publishProgress(i);
                try {
                    Thread.sleep(1000);
                    i++;
                } catch(Exception e) {

                }
            }

            return "Button Pressed";
        }
    }
}

The Logcat output (created by the Log.i items added by me for troubleshooting) is usually the below but if the warning message that advises the app keeps crashing pops up the "before publish" item keeps populating with i incrementing each time until I close the warning message:

2020-12-13 23:17:04.499 31729-31772/com.ebookfrenzy.asyncdemo I/Test: before publish: 0
2020-12-13 23:17:04.503 31729-31729/com.ebookfrenzy.asyncdemo I/Test: publish: 0

The error section of the Logcat:

    --------- beginning of crash
2020-12-13 23:19:47.635 353-353/com.ebookfrenzy.asyncdemo E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.ebookfrenzy.asyncdemo, PID: 353
    java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
        at com.ebookfrenzy.asyncdemo.MainActivity$MyTask.onProgressUpdate(MainActivity.java:34)
        at com.ebookfrenzy.asyncdemo.MainActivity$MyTask.onProgressUpdate(MainActivity.java:25)
        at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:715)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2020-12-13 23:19:47.639 353-353/com.ebookfrenzy.asyncdemo I/Process: Sending signal. PID: 353 SIG: 9

Solution

  • I think myTextView must be null.

    Try this.

    if (myTextView != null){
      myTextView.setText("Counter = " + values[0]);
    }
    

    And you should initialize myTextView at onCreate() method.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myTextView = (TextView) findViewById(R.id.mytextviewid); // put 
    }