Android basics: running code in the UI thread

2018-12-31 23:41发布

问题:

In the viewpoint of running code in the UI thread, is there any difference between:

MainActivity.this.runOnUiThread(new Runnable() {
    public void run() {
        Log.d(\"UI thread\", \"I am the UI thread\");
    }
});

or

MainActivity.this.myView.post(new Runnable() {
    public void run() {
        Log.d(\"UI thread\", \"I am the UI thread\");
    }
});

and

private class BackgroundTask extends AsyncTask<String, Void, Bitmap> {
    protected void onPostExecute(Bitmap result) {
        Log.d(\"UI thread\", \"I am the UI thread\");
    }
}

回答1:

None of those are precisely the same, though they will all have the same net effect.

The difference between the first and the second is that if you happen to be on the main application thread when executing the code, the first one (runOnUiThread()) will execute the Runnable immediately. The second one (post()) always puts the Runnable at the end of the event queue, even if you are already on the main application thread.

The third one, assuming you create and execute an instance of BackgroundTask, will waste a lot of time grabbing a thread out of the thread pool, to execute a default no-op doInBackground(), before eventually doing what amounts to a post(). This is by far the least efficient of the three. Use AsyncTask if you actually have work to do in a background thread, not just for the use of onPostExecute().



回答2:

I like the one from HPP comment, it can be used anywhere without any parameter:

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Log.d(\"UI thread\", \"I am the UI thread\");
    }
});


回答3:

There is a fourth way using Handler

new Handler().post(new Runnable() {
    @Override
    public void run() {
        // Code here will run in UI thread
    }
});


回答4:

The answer by Pomber is acceptable, however I\'m not a big fan of creating new objects repeatedly. The best solutions are always the ones that try to mitigate memory hog. Yes, there is auto garbage collection but memory conservation in a mobile device falls within the confines of best practice. The code below updates a TextView in a service.

TextViewUpdater textViewUpdater = new TextViewUpdater();
Handler textViewUpdaterHandler = new Handler(Looper.getMainLooper());
private class TextViewUpdater implements Runnable{
    private String txt;
    @Override
    public void run() {
        searchResultTextView.setText(txt);
    }
    public void setText(String txt){
        this.txt = txt;
    }

}

It can be used from anywhere like this:

textViewUpdater.setText(\"Hello\");
        textViewUpdaterHandler.post(textViewUpdater);


回答5:

If you need to use in Fragment you should use

private Context context;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.context = context;
    }


    ((MainActivity)context).runOnUiThread(new Runnable() {
        public void run() {
            Log.d(\"UI thread\", \"I am the UI thread\");
        }
    });

instead of

getActivity().runOnUiThread(new Runnable() {
    public void run() {
        Log.d(\"UI thread\", \"I am the UI thread\");
    }
});

Because There will be null pointer exception in some situation like pager fragment



回答6:

As of Android P you can use getMainExecutor():

getMainExecutor().execute(new Runnable() {
  @Override public void run() {
    // Code will run on the main thread
  }
});

From the Android developer docs:

Return an Executor that will run enqueued tasks on the main thread associated with this context. This is the thread used to dispatch calls to application components (activities, services, etc).

From the CommonsBlog:

You can call getMainExecutor() on Context to get an Executor that will execute its jobs on the main application thread. There are other ways of accomplishing this, using Looper and a custom Executor implementation, but this is simpler.



回答7:

hi guys this one is basic question any away i tell

use Handler

new Handler().post(new Runnable() {
    @Override
    public void run() {
        // Code here will run in UI thread
    }
});