С точки зрения запуска кода в потоке пользовательского интерфейса, есть ли разница между:
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");
}
}
Ответы:
Ни один из них не является абсолютно одинаковым, хотя все они будут иметь одинаковый чистый эффект.
Разница между первым и вторым, что если вам случится быть на главном потоке приложения при выполнении кода, первый один (
runOnUiThread()
) будет выполнятьсяRunnable
немедленно. Второйpost()
метод ( ) всегда ставитRunnable
в конец очередь событий, даже если вы уже находитесь в главном потоке приложения.Третий, предполагая, что вы создаете и выполняете экземпляр
BackgroundTask
, потратит много времени на извлечение потока из пула потоков, чтобы выполнить no-op по умолчаниюdoInBackground()
, прежде чем в конечном итоге сделать то, что равно apost()
. Это, безусловно, наименее эффективный из трех. Используйте,AsyncTask
если у вас действительно есть работа в фоновом потоке, а не только для использованияonPostExecute()
.источник
AsyncTask.execute()
в любом случае требуется , чтобы вы вызывали из потока пользовательского интерфейса, что делает эту опцию бесполезной для случая использования простого запуска кода в потоке пользовательского интерфейса из фонового потока, если только вы не переместили всю свою фоновую работуdoInBackground()
и не использовали ееAsyncTask
должным образом.AsyncTask
из потока пользовательского интерфейса?boolean isUiThread = (Looper.getMainLooper().getThread() == Thread.currentThread());
Looper.getMainLooper().isCurrentThread
Мне нравится комментарий из ГЭС , его можно использовать где угодно без каких-либо параметров:
источник
Существует четвертый способ использования
Handler
источник
new Handler(Looper.getMainLooper()).post(r)
, что является предпочтительным способом, так какLooper.getMainLooper()
делает статический вызов main, тогда какpostOnUiThread()
должен иметь экземплярMainActivity
в области видимости.Ответ Помбера приемлем, однако я не большой поклонник создания новых объектов неоднократно. Лучшие решения - это всегда те, которые пытаются уменьшить нагрузку на память. Да, есть автоматическая сборка мусора, но сохранение памяти в мобильном устройстве находится в пределах наилучшей практики. Код ниже обновляет TextView в сервисе.
Его можно использовать откуда угодно:
источник
The best solutions are always the ones that try to mitigate memory hog
. Есть много других критериевbest
, и это имеет легкий запахpremature optimization
. То есть, если вы не знаете, что называете это достаточно, что количество созданных объектов является проблемой (по сравнению с десятью тысячами других способов, которыми ваше приложение, вероятно, создает мусор.), Что может бытьbest
написанием самого простого (самого простого для понимания ) и перейдите к другой задаче.textViewUpdaterHandler
лучше было бы назвать что-то вродеuiHandler
илиmainHandler
, так как это обычно полезно для любого сообщения в основной теме пользовательского интерфейса; он совсем не привязан к вашему классу TextViewUpdater. Я бы отодвинул его от остальной части этого кода и дал бы понять, что его можно использовать в другом месте ... Остальная часть кода сомнительна, потому что во избежание динамического создания одного объекта вы разбиваете то, что может быть одним вызовом, на два шага,setText
иpost
это зависит от долгоживущего объекта, который вы используете в качестве временного. Ненужная сложность, а не потокобезопасность. Не легко поддерживать.uiHandler
иtextViewUpdater
, затем улучшить свой класс, изменив значение параметраpublic void setText(String txt, Handler uiHandler)
и добавления метода линииuiHandler.post(this);
Затем вызывающий абонент может сделать один шаг:textViewUpdater.setText("Hello", uiHandler);
. Затем в будущем, если это необходимо для обеспечения безопасности потоков, метод может заключить свои операторы в блокировкуuiHandler
, и вызывающая сторона останется неизменной.Начиная с Android P вы можете использовать
getMainExecutor()
:Из документации для разработчиков Android :
Из CommonsBlog :
источник
Если вам нужно использовать во фрагменте, вы должны использовать
вместо
В некоторых ситуациях, таких как фрагмент пейджера, будет исключение нулевого указателя
источник
Привет, ребята, это один из основных вопросов, я говорю
использовать обработчик
источник
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
если он не вызывается из потока пользовательского интерфейса.