Основы 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()
}
Другие вопросы по тегам