In one of my app, I have a scenario where I need to do some background task. For doing that I am using Async Task. Also I am using custom progress dialog. Below is the layout of the custom progress dialog
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|center_horizontal"
android:orientation="vertical" >
<ProgressBar
android:layout_width="60dp"
android:layout_height="60dp"
android:indeterminateDrawable="@drawable/progressloader"
android:layout_gravity="center"/>
<TextView
android:id="@+id/progressMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="18sp"
android:text="Please wait...." />
</LinearLayout>
Everything works fine but when I try to set text to TextView then I am getting java NullPointerException.
AsyncTask code
private class InitialSetup extends AsyncTask<String, Integer, Long> {
ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);
@Override
protected void onPreExecute() {
dialog.show();
dialog.setContentView(R.layout.progressbar);
}
@Override
protected Long doInBackground(String... urls) {
// txtView.setText("Testing"); here I am getting the error
fetchDetails();
return 0;
}
@Override
protected void onPostExecute(Long result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
populateUI(getApplicationContext());
}
}
MainActivity
public class SummaryActivity extends Activity {
final TextView txtView = (TextView)findbyid(R.id.progressMessage);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.accountsummary);
new InitialSetup().execute("");
}
}
Yes, because you are trying to set the TextView inside the doInBackground() method, and this is not allowed,
Why not allowed? Because There is a only one Thread running which is UI Main Thread, and it doesn't allowed to update UI from thread process. read more info here: Painless Threading
So there is a solution if you want to set the TextView inside the doInBackground() method, do the UI updating operations inside the runOnUiThread method.
Otherwise, suggestion is to do all the UI display/update related operations inside the onPostExecute() method instead of doInBackground() method of your AsyncTask class.
The explanations are correct: You are not to make UI changes in any thread except the thread which create the UI. But AsyncTask has a method called
which always will run in the UI Thread. So based on the modifications by dennisg your code should look like this:
Note that the type of the parameter of onProgressUpdate is the second type given in AsyncTask!
Extra: To make your code more robust you should check if the progress dialog still exists before setting the text.
If I understand correctly, your
TextView
of which you want to set the text can be found in the xml file progressbar.xml (i.e.R.layout.progressbar
). ThisTextView
can be obtained once the content view has been set (usingsetContentView()
). In your code you set it before this call is been and the code of mussharapp, he is calling it to early. Namely, he calls it after thesetContentView(R.layout.accountsummary)
call which does not contain theTextView
. Consequently, the variabletxtView
will be NULL and you will get aNullPointerException
.What you should do is the following:
onPreExecute
, aftersetContentView
is called.For the code look down below:
should only be executed after the command setContentView().
Also you can only change UI elements in the main UI thread. doInBackground() is not in the main UI thread. Make UI changes in onPostExecute