Updating TextView from Async Task which use custom program dialog

前端 未结 4 1666
天命终不由人
天命终不由人 2020-12-10 08:29

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 layou

相关标签:
4条回答
  • 2020-12-10 08:43

    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.

    0 讨论(0)
  • 2020-12-10 08:46

    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

    onProgressUpdate()
    

    which always will run in the UI Thread. So based on the modifications by dennisg your code should look like this:

    private class InitialSetup extends AsyncTask<String, String, Long> {
    
        ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);
        // The variable is moved here, we only need it here while displaying the
        // progress dialog.
        TextView txtView;
    
        @Override
        protected void onPreExecute() {
            dialog.show();
            dialog.setContentView(R.layout.progressbar);
            // Set the variable txtView here, after setContentView on the dialog
            // has been called! use dialog.findViewById().
            txtView = dialog.findViewById(R.id.progressMessage); 
        }
    
        @Override
        protected Long doInBackground(String... urls) {
            publishProgress("Testing");
    
            fetchDetails();
    
            return 0;
        }
    
        @Override
        protected void onPostExecute(Long result) {
    
            if (this.dialog.isShowing()) {
                this.dialog.dismiss();
            }
    
            populateUI(getApplicationContext());
        }
    
        @Override
        protected void onProgressUpdate(String... update) {
            if (update.length > 0)
                txtView.setText(update[0]); 
        }
    }
    

    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.

    0 讨论(0)
  • 2020-12-10 08:57
    (TextView)findViewByid(R.id.progressMessage);
    

    should only be executed after the command setContentView().

    TextView txtView;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.accountsummary);
        **txtView = (TextView)findbyid(R.id.progressMessage);**
    
    
        new InitialSetup().execute("");
    
    }
    

    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

    public class InitialSetup extends AsyncTask<String, Integer, Long> {
    
            private Activity activity;
            ProgressDialog progressDialog;
    
            public InitialSetup(Activity activity) {
                this.activity = activity;
            }
    
    
    
    
            @Override
            protected void onPreExecute() {
                progressDialog = new ProgressDialog(activity);
                progressDialog.setMessage("Starting task....");
                progressDialog.show();    
            }
    
            @Override
            protected Long doInBackground(String... urls) {
                // do something
    
                //        
    
                return 0;
            }
    
            @Override
            protected void onPostExecute(Long result) {
                progressDialog.dismiss();
                 //Perform all UI changes here
                **textView.setText("Text#2");**
            }
        }
    
    0 讨论(0)
  • 2020-12-10 08:58

    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). This TextView can be obtained once the content view has been set (using setContentView()). 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 the setContentView(R.layout.accountsummary) call which does not contain the TextView. Consequently, the variable txtView will be NULL and you will get a NullPointerException.

    What you should do is the following:

    • Set the variable txtView in onPreExecute, after setContentView is called.
    • Based on Paresh Mayani's explanation: Use the runOnUiThread method.

    For the code look down below:

    private class InitialSetup extends AsyncTask<String, Integer, Long> {
    
            ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);
            // The variable is moved here, we only need it here while displaying the
            // progress dialog.
            TextView txtView;
    
            @Override
            protected void onPreExecute() {
                dialog.show();
                dialog.setContentView(R.layout.progressbar);
                // Set the variable txtView here, after setContentView on the dialog
                // has been called! use dialog.findViewById().
                txtView = dialog.findViewById(R.id.progressMessage); 
            }
    
            @Override
            protected Long doInBackground(String... urls) {
                // Already suggested by Paresh Mayani:
                // Use the runOnUiThread method.
                // See his explanation.
                runOnUiThread(new Runnable() {
                   @Override
                   public void run() {
                      txtView.setText("Testing");       
                   }
                });
    
                fetchDetails();
                return 0;
            }
    
            @Override
            protected void onPostExecute(Long result) {
    
                if (this.dialog.isShowing()) {
                    this.dialog.dismiss();
                }
    
                populateUI(getApplicationContext());
            }
        }
    
    0 讨论(0)
提交回复
热议问题