Android: когда мне следует использовать Handler (), а когда - поток?

129

Когда мне нужно что-то для асинхронного запуска , например, длительная задача или логика, использующая сеть, или по любой другой причине, запуск нового потока и его выполнение работает нормально. Создание и запуск обработчика тоже работает. Какая разница? Когда я должен использовать каждый из них? Каковы преимущества / причины использования a, Handlerа не a Thread?

PS. - Ради этого вопроса давайте проигнорируем AsyncTask. - Handler().postDelayedвариант использования мне понятен, поэтому давайте предположим, что мне нужно, чтобы задача запускалась немедленно.

JRun
источник
В вашей ситуации просто идите вперед и используйте новый поток, моим следующим предложением будет AsyncTask, но это явно не то, что вам нужно. Обработчики в основном используются, если вы хотите добавить задержку или какой-либо другой тип настройки в исполняемый файл.
kabuto178
1
@ kabuto178 ну, стоит упомянуть и о других преимуществах обработчиков, которые вы пропустили. Например, возможность взаимодействовать с потоком пользовательского интерфейса из отдельного потока ..
tony9099

Ответы:

168

Если все, что вы делаете, «тяжело», вы должны делать это в потоке. Если вы явно не запускаете его в собственном потоке, он будет работать в основном (UI) потоке, который может быть заметен пользователями как нестабильный или медленный интерфейс.

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

Типичное взаимодействие потока / обработчика может выглядеть примерно так:

Handler h = new Handler(){
    @Override
    public void handleMessage(Message msg){
        if(msg.what == 0){
            updateUI();
        }else{
            showErrorDialog();
        }
    }
};

Thread t = new Thread() {
    @Override
    public void run(){
        doSomeWork();
        if(succeed){
            //we can't update the UI from here so we'll signal our handler and it will do it for us.
            h.sendEmptyMessage(0);
        }else{
            h.sendEmptyMessage(1);
        }
    }   
};

В целом, можно сделать вывод, что вы должны использовать поток каждый раз, когда выполняете какую-либо работу, которая может быть длительной или очень интенсивной (например, что-либо сетевое, файловый ввод-вывод, тяжелая арифметика и т. Д.).

FoamyGuy
источник
Спасибо за быстрый ответ и потраченное время (а также за скорость ответа !!)! Итак, позвольте мне посмотреть, понял ли я: обработчик предназначен для облегчения неблокирующей связи между рабочими потоками и потоком пользовательского интерфейса?
JRun
3
@JRun Это одно из применений, да. Ознакомьтесь с описанием обработчика в документации по java, чтобы получить полезную информацию о нем. Включая другое его использование (для планирования сообщений и исполняемых файлов, которые будут выполняться в какой-то момент в будущем).
FoamyGuy
красиво объяснил @FoamyGuy!
tony9099
Привет, это гарантировано, что updateUI()запустится после onCreateView(после загрузки новых представлений)?
Zyoo 07
1
Почему это message.what()? Разве это не было бы просто if(msg == 0){? Спасибо! :)
Ruchir Baronia
65

Обработчик и поток - это две разные вещи.

Для выполнения длительных заданий необходимо создать поток.

Обработчик - очень удобный объект для связи между двумя потоками (например: фоновый поток должен обновлять пользовательский интерфейс. Вы можете использовать обработчик для публикации некоторого Runnable из фонового потока в поток пользовательского интерфейса).

Таким образом, у вас нет выбора между обработчиком или потоком. Используйте нить для тяжелой работы! (вы можете использовать обработчик, если ваш фоновый поток инициирует выполнение некоторой работы в другом потоке - большую часть времени поток пользовательского интерфейса)

ben75
источник
Спасибо за быстрый ответ и потраченное время (а также за скорость ответа !!)!
JRun
28

Handlerи Threadэто две разные вещи, но они не противоречат друг другу. У вас могут быть a Handlerи a Threadодновременно, и фактически каждый из них Handlerдолжен работать в a Thread.

Для получения дополнительных сведений ознакомьтесь с этой статьей .

введите описание изображения здесь

pierrotlefou
источник
19

A Handlerработает в одном потоке Thread, a Threadвыполняется в другом потоке.

Используйте обработчик, если вам нужно запустить что-то в том же потоке , обычно это элемент графического интерфейса или что-то в этом роде.

Используйте поток, если вы хотите, чтобы основной поток мог заниматься другими делами . Используйте это для всего, что требует много времени.

PearsonArtPhoto
источник
6
зачем мне использовать обработчик, если я хочу запустить что-то в том же потоке? какова цель метода mHandler.post (...)?
Elias
1
Элиас, в таком случае вы можете использовать обработчик, если хотите, чтобы определенная задача выполнялась через определенный промежуток времени или повторяла задачу каждые X промежутков времени. Если вы не хотите использовать эти вещи, вы правы. использовать обработчик недостойно. вы можете просто делать вещи с графическим интерфейсом прямо сейчас, bcoz вы в любом случае находитесь в потоке пользовательского интерфейса, потому что обработчик работает в потоке, в котором он был создан.
tony9099
14

Обработчики - лучший способ связи между фоном и потоком пользовательского интерфейса. Обычно обработчики связаны с очередью сообщений потока, и они используются для отправки сообщений и запускаются в сообщении.

ОБЛАСТЬ ПРИМЕНЕНИЯ:

Тема: для выполнения задач в более безопасном (фоновом) потоке, чем поток пользовательского интерфейса. (помогает разблокировать поток пользовательского интерфейса)

Обработчик Используется для связи между пользовательским интерфейсом и фоновым потоком.

Взгляните на эту статью

Саубхагья Ранджан Дас
источник
4

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

Для этого можно использовать класс android.os.Handler или класс AsyncTasks.

Класс Handler может обновлять пользовательский интерфейс. Обработчик предоставляет методы для получения экземпляров класса Message или Runnable.

Вы можете публиковать сообщения с помощью метода sendMessage (Message msg) или метода sendEmptyMessage ().

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

Beachwalker
источник
Спасибо, что нашли время ответить на мой вопрос. Мне нравится блог Ларса Фогеля, он очень информативный, и за ним легко следить. Спасибо!
JRun
2

Каковы преимущества / причины использования обработчика, а не потока?

Handler позволяет передавать и обрабатывать сообщения и Runnableобъекты , связанные с потока MessageQueue. каждыйHandler экземпляр связан с одним потоком и очередью сообщений этого потока.

Когда вы создаете новый Handler , он привязывается к потоку / очереди сообщений потока, который его создает - с этого момента он будет доставлять сообщения и исполняемые файлы в эту очередь сообщений и выполнять их, когда они выходят из очереди сообщений. ,

Есть два основных применения обработчика:

  1. Чтобы запланировать выполнение сообщений и Runnables в какой-то момент в будущем
  2. Чтобы поставить в очередь действие, которое будет выполняться в другом потоке, чем ваш собственный.

Если вы используете потоки Java, вам придется кое-что решать самостоятельно - синхронизацию с основным потоком, отмена потока и т. Д.

Этот единственный поток не создает пул потоков, если вы не используете API ThreadPoolExecutorили ExecutorService.

(Этот запрос взят из ваших комментариев к ответу Blackbelt)

Почему бы не использовать Executor? и даже если бы я хотел использовать для этого Handler, как?

Ссылка: статья о производительности потоков

Есть определенные виды работы, которые можно свести к высоко параллельным распределенным задачам. С большим объемом работы пакетов это создает, AsyncTaskа HandlerThreadне соответствующие классы. Однопоточная природа AsyncTaskпревратит всю работу с пулом потоков в линейную систему. С HandlerThreadдругой стороны, использование класса потребует от программиста ручного управления балансировкой нагрузки между группой потоков.

ThreadPoolExecutor - это вспомогательный класс, упрощающий этот процесс. Этот класс управляет созданием группы потоков, устанавливает их приоритеты и управляет распределением работы между этими потоками. По мере увеличения или уменьшения рабочей нагрузки класс раскручивает или уничтожает больше потоков, чтобы приспособиться к рабочей нагрузке.

 BlockingQueue workQueue= new LinkedBlockingQueue<Runnable>(100); // Work pool size
 ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),       // Initial pool size
            Runtime.getRuntime().availableProcessors(),       // Max pool size
            1, // KEEP_ALIVE_TIME
            TimeUnit.SECONDS, //  KEEP_ALIVE_TIME_UNIT
            workQueue);

Вы можете обратиться к этой статье руководства разработчика о create-threadpool для получения дополнительных сведений.

Взгляните на этот пост для использования Handlerдля запуска нескольких экземпляров Runnable. В этом случае все Runnableзадачи будут выполняться в одном потоке.

Android: тост в ветке

Равиндра бабу
источник
1

Handlerможет использоваться вместе с Threadдля создания механизма очереди. Uвы можете использовать, handlerчтобы опубликовать что-нибудь вThread Looper

Черный пояс
источник
Спасибо, что нашли время ответить на мой вопрос. Почему бы не использовать Executor? и даже если бы я хотел использовать для этого Handler, как?
JRun
исполнитель немного другой. Чтобы использовать его, вы должны расширить поток и в ходе выполнения вызвать static.metohd prepare.of класса Looper. после вызова цикла статического метода создается очередь, и вы можете использовать команду handlerbin для пересылки запросов и получения результатов обратно
Blackbelt,