Основы Android: запуск кода в потоке пользовательского интерфейса
С точки зрения запуска кода в потоке пользовательского интерфейса, есть ли разница между:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
или же
MainActivity.this.myView.post(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
а также
private class BackgroundTask extends AsyncTask<String, Void, Bitmap> {
protected void onPostExecute(Bitmap result) {
Log.d("UI thread", "I am the UI thread");
}
}
8 ответов
Ни одно из них не является абсолютно одинаковым, хотя все они будут иметь одинаковый чистый эффект.
Разница между первым и вторым заключается в том, что если вы выполняете код в основном потоке приложения, то первый (runOnUiThread()
) выполнит Runnable
немедленно. Второй (post()
) всегда ставит Runnable
в конце очереди событий, даже если вы уже находитесь в главном потоке приложений.
Третий, предполагая, что вы создаете и выполняете экземпляр BackgroundTask
, потратит много времени на извлечение потока из пула потоков для выполнения по умолчанию no-op doInBackground()
прежде чем в конечном итоге делать то, что составляет post()
, Это, безусловно, наименее эффективный из трех. использование AsyncTask
если у вас действительно есть работа в фоновом потоке, а не только для использования onPostExecute()
,
Мне нравится комментарий из ГЭС, его можно использовать где угодно без каких-либо параметров:
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
Существует четвертый способ использования Handler
new Handler().post(new Runnable() {
@Override
public void run() {
// Code here will run in UI thread
}
});
Ответ Помбера приемлем, однако я не большой поклонник создания новых объектов неоднократно. Лучшие решения - это всегда те, которые пытаются смягчить нагрузку на память. Да, есть автоматическая сборка мусора, но сохранение памяти в мобильном устройстве находится в пределах наилучшей практики. Код ниже обновляет TextView в сервисе.
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;
}
}
Его можно использовать откуда угодно:
textViewUpdater.setText("Hello");
textViewUpdaterHandler.post(textViewUpdater);
Если вам нужно использовать во фрагменте, вы должны использовать
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");
}
});
вместо
getActivity().runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
В некоторых ситуациях, таких как фрагмент пейджера, будет исключение нулевого указателя
Начиная с Android P вы можете использовать getMainExecutor()
:
getMainExecutor().execute(new Runnable() {
@Override public void run() {
// Code will run on the main thread
}
});
Из документации для разработчиков Android:
Вернуть Исполнителя, который будет запускать поставленные в очередь задачи в главном потоке, связанном с этим контекстом. Это поток, используемый для отправки вызовов компонентам приложения (действиям, службам и т. Д.).
Из CommonsBlog:
Вы можете вызвать getMainExecutor() для Context, чтобы получить Executor, который будет выполнять свои задания в главном потоке приложения. Есть другие способы сделать это, используя Looper и пользовательскую реализацию Executor, но это проще.
Привет, ребята, это один из основных вопросов, я говорю
использовать обработчик
new Handler().post(new Runnable() {
@Override
public void run() {
// Code here will run in UI thread
}
});
Котлин версия:
Handler(Looper.getMainLooper()).post {
Toast.makeText(context, "Running on UI(Main) thread.", Toast.LENGTH_LONG).show()
}
Или, если вы используете сопрограммы Kotlin: внутри области сопрограммы добавьте следующее:
withContext(Dispatchers.Main) {
Toast.makeText(context, "Running on UI(Main) thread.", Toast.LENGTH_LONG).show()
}