Best practices of notifying UI components from Asy

2019-04-15 13:23发布

问题:

I've been reading to use AsyncTask class to do shorter background operations, and services for long lasting operations.

So what are the best practices in Android to notify UI about changes in background processes when using AsyncTask class? Should I use classic MVC model and create a listener (preferably in class extending Application class) or is there a standart way of doing this in Android?

I've read AsyncTask reference and it seems method onProgressUpdate() is only useful when using ProgressDialog in the task itself for example.

Thanks!

回答1:

If the component to update is the component that starts the update Job (through AsyncTask or Service), you should probably use an inner AsyncTask

AsyncTask offers you two posibilites to update the UI :

  • To update the UI in parallel with the task executed in doInBackground() (e.g. to update a ProgressBar), you'll have to call publishProgress() inside the doInBackground() method. Then you have to update the UI in the onProgressUpdate() method.
  • To update the UI when the task is done, you have to do it in the onPostExecute() method.

see :
doInBackground()
publishProgress()
onProgressUpdate()
onPostExecute()

Edit :

public class Home extends Activity implements OnClickListener {
    private Button mButton;
    private TextView mTextView;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_layout);
        mButton   = (Button) findViewById(R.id.myButton);
        mTextView = (TextView) findViewById(R.id.myTextView);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
        case R.id.myButton:
            (new MyAsyncTask()).execute();
            break;
        default:
            break;
        }
    }

    private class MyAsyncTask extends AsyncTask<String, int[], Boolean> {

        /** This method runs on a background thread (not on the UI thread) */
        @Override
        protected String doInBackground(String... params) {
            for (int progressValue = 0; progressValue  < 100; progressValue++) {
                publishProgress(progressValue);
            }
        }

        /** This method runs on the UI thread */
        @Override
        protected void onProgressUpdate(Integer... progressValue) {
            // TODO Update your ProgressBar here
            mTextView.setText("Updating : " + progressValue + "/100");
        }

        /**
         * Called after doInBackground() method
         * This method runs on the UI thread
         */
        @Override
        protected void onPostExecute(Boolean result) {
           // TODO Update the UI thread with the final result
           mTextView.setText("Update complete !");

        }
    }
}

You can find another example here.



回答2:

OnProgressUpdate is the way to go. When you declare you implementation of the AsyncTask, you can define an object to be sent back via onProgressUpdate which can be processed to send updates to your UI. Otherwise if you implement a listener if you attempt to change the UI you will have a Thread violation since the AsyncTask is executing in a thread outside of the application's main thread. Any code within onProgessUpdate is executed in the callers Main thread so it can update the UI without any problems



回答3:

AsyncTask vs service- use an AsyncTask when the result is local to your activity- when other activities don't need the result of your task. Use a service when they do.

Use onPorgressUpdate to provide incremental status notifications in an AsyncTask- any notifications when the task is not yet done. For notifications of when the task is done, use onPostExecute. A listener may also be appropriate, but only if you need to notify a specific class which isn't necessarily known at compile time, not for a generic way of posting status updates.