Основы 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");
    }
}

Ответ 1

Ни один из них не является тем же самым, хотя все они будут иметь одинаковый сетевой эффект.

Разница между первой и второй заключается в том, что если вы выполняете основной поток приложения при выполнении кода, первый (runOnUiThread()) немедленно выполнит Runnable. Второй (post()) всегда помещает Runnable в конец очереди событий, даже если вы уже находитесь в главном потоке приложения.

Третий, предполагая, что вы создаете и выполняете экземпляр BackgroundTask, будет тратить много времени на захват потока из пула потоков, чтобы выполнить по умолчанию no-op doInBackground(), прежде чем, в конце концов, сделать какие суммы до post(). Это, безусловно, наименее эффективный из трех. Используйте AsyncTask, если на самом деле у вас есть работа в фоновом потоке, а не только на использование onPostExecute().

Ответ 2

Мне нравится комментарий HPP, его можно использовать где угодно без каких-либо параметров:

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

Ответ 3

Существует четвертый способ использования Handler

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

Ответ 4

Ответ Pomber приемлем, однако я не большой поклонник создания новых объектов повторно. Лучшими решениями всегда являются те, которые пытаются уменьшить волну памяти. Да, есть сбор мусора, но сохранение памяти в мобильном устройстве находится в пределах передового опыта. Код ниже обновляет 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);

Ответ 5

Если вам нужно использовать в Фрагменте, вы должны использовать

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");
    }
});

Потому что в некоторой ситуации, такой как фрагмент пейджера, будет исключение с нулевым указателем

Ответ 6

С Android P вы можете использовать getMainExecutor():

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

Из Android-разработчиков:

Верните Исполнителя, который будет запускать заданные задачи в основном потоке, связанном с этим контекстом. Это поток, используемый для отправки вызовов компонентам приложения (действия, службы и т.д.).

Из CommonsBlog:

Вы можете вызвать getMainExecutor() в Контексте, чтобы получить Исполнитель, который выполнит свои задания в главном потоке приложения. Существуют и другие способы достижения этого, используя Looper и пользовательскую реализацию Executor, но это проще.

Ответ 7

привет, ребята, это основной вопрос в любом случае, я говорю

использовать обработчик

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

Ответ 8

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

});

работает для меня. Спасибо!