Потоки
Потоки позволяют выполнять несколько задач одновременно, не мешая друг другу, что даёт возможность эффективно использовать системные ресурсы. Потоки используются в тех случаях, когда одно долгоиграющее действие не должно мешать другим действиям. Например, у нас есть музыкальный проигрыватель с кнопками воспроизведения и паузы. Если вы нажимаете кнопку воспроизведения и у вас запускается музыкальный файл в отдельном потоке, то вы не можете нажать на кнопку паузы, пока файл не воспроизведётся полностью. С помощью потоков вы можете обойти данное ограничение.
Использование фоновых потоков
Чтобы быть уверенным, что ваше приложение не теряет отзывчивости, хорошим решением станет перемещение всех медленных, трудоёмких операций из главного потока приложения в дочерний.
Применение фоновых потоков — необходимое условие, если вы хотите избежать появления диалогового окна для принудительного закрытия приложения. Когда активность в Android на протяжении 5 секунд не отвечает на события пользовательского ввода (например, нажатие кнопки) или приёмник широковещательных намерений не завершает работу обработчика onReceive() в течение 10 секунд, считается, что приложение зависло. Подобные ситуации следует избегать любой ценой. Используйте фоновые потоки для всех трудоёмких операций, включая работу с файлами, сетевые запросы, транзакции в базах данных и сложные вычисления.
Android предоставляет несколько механизмов перемещения функциональности в фоновый режим.
- Activity.runOnUiThread(Runnable)
- View.post(Runnable)
- View.postDelayed(Runnable, long)
- Handlers
- AsyncTask
Класс AsyncTask позволяет определить операции, которые будут выполняться в фоне, вы также будете иметь доступ к обработчику событий, что позволит отслеживать прогресс выполнения задач и выводить результаты в контексте главного графического потока. Подробнее об этом классе в отдельной статье.
Хотя использование AsyncTask — хорошее решение, случается, что для работы в фоновом режиме приходится создавать собственные потоки и управлять ими.
В Java есть стандартный класс Thread, который вы можете использовать следующим образом:
Данный способ подходит только для операций, связанных с временем. Но вы не сможете обновлять графический интерфейс программы.
Если вам нужно обновлять интерфейс программы, то нужно использовать AsyncTask, о котором говорилось выше, или вы можете реализовать ваш собственный класс, наследованный от Thread, используя объект Handler из пакета android.os для синхронизации с потоком GUI перед обновлением пользовательского интерфейса.
Вы можете создавать дочерние потоки и управлять ими с помощью класса Handler, а также классов, доступных в пространстве имён java.lang.Thread. Ниже показан простой каркас для переноса операций в дочерний поток.
Плохое приложение
Напишем «плохое» приложение, неправильно использующее основной поток. Однажды мы писали программу для подсчёта ворон. На этот раз будем считать чёрных котов, которые перебегают нам дорогу. Зачем они это делают — молчит наука. Может быть собранная статистика поможет разгадать тайну. Добавим на экран активности кнопки и текстовую метку. Код для щелчка кнопки.
Для имитации тяжёлой работы программа делает паузу на двадцать секунд, а потом выводит текст с подсчётом котов. Если нажать на кнопку один раз и подождать двадцать секунд, то программа отработает как положено. Но представьте себе, что вы нажали на кнопку один раз. Программа запустила паузу. Вы, не дожидаясь окончания паузы, снова нажали на кнопку. Программа должна выполнить вашу команду, но предыдущая команда ещё не отработала и наступает конфликт. Попробуйте нажать на кнопку несколько раз с небольшими перерывами. В какой-то момент приложение зависнет и выведет системное диалоговое окно:
В реальных приложениях такое окно может разозлить пользователя и он поставит низкую оценку вашему приложению.
В данном случае ошибку вызывает не сам вывод текста в текстовой метке, который, к слову, тоже выполняется в основном потоке, а сам щелчок кнопки. Если вы закомментируете последние две строчки кода, связанные с TextView, то ошибка сохранится.
Вам необходимо перенести трудоёмкую задачу в отдельный поток. Для этого создаётся экземпляр класса Runnable, у которого есть метод run(). Далее создаётся объект Thread, в конструкторе у которого указывается созданный Runnable. После этого можно запускать новый поток с помощью метода start(). Перепишем пример.
Весь код мы перенесли в метод run(). Теперь вы можете безостановочно щёлкать по кнопке. На этот раз приложение сохранит свою работоспособность. Чтобы в этом убедиться, в код добавлено протоколирование логов Log.i(). При каждом нажатии создаётся новый поток, в котором выполняется код. Потоки друг другу не мешают и дожидаются своей очереди, когда система позволит им отработать.
Основной поток также называют UI-потоком. Имено в главном потоке можно обновить текст у текстовой метки. В создаваемых нами потоках это делать нельзя. Если вы уберёте комментарии с последнего примера и запустите проект, то получите сообщение об ошибке.
Нужен некий посредник между создаваемыми потоками и основным UI-потоком. В роли такого посредника служит класс Handler (полное название класса android.os.Handler, не перепутайте). Вам нужно создать экземпляр класса и указать код, который нужно выполнить.
После строчки кода с Log.i() добавьте вызов метода посредника.
Поток вызывает посредника, который в свою очередь обновляет интерфейс. В нашем случае посредник посылает пустое сообщение от потока.
Но бывает так, что от потока требуется получить информацию для обработки. Ниже упрощённый пример.
Запуск потока
Предположим, мы разрабатываем собственный проигрыватель. У нас есть кнопка Play, которая вызывает метод play() для воспроизведения музыки:
Теперь запустим метод в другом потоке. Сначала создаётся новый поток. Далее описывается объект Runnable в конструкторе потока. А внутри созданного потока вызываем наш метод play(). И, наконец, запускаем поток.
Усыпить поток
Иногда требуется временно приостановить поток («усыпить»):
Приоритет потоков
Для установки приоритета процесса используется метод setPriority(), который вызывается до запуска потока. Значение приоритета может варьироваться от Thread.MIN_PRIORITY (1) до Thread.MAX_PRIORITY (10):
Отмена выполнения потока
У потока есть метод stop(), но использовать его не рекомендуется, поскольку он оставляет приложение в неопределённом состоянии. Обычно используют такой подход:
Существует и другой способ, когда все запускаемые потоки объявляются демонами. В этом случае все запущенные потоки будут автоматически завершены при завершении основного потока приложения:
Источник
Как приостановить / спать поток или процесс в Android?
Я хочу сделать паузу между двумя строками кода, позвольте мне объяснить немного:
-> пользователь нажимает кнопку (фактически карту), и я показываю ее, изменяя фон этой кнопки:
-> после, скажем, 1 секунды, мне нужно вернуться к предыдущему состоянию кнопки, изменив ее фон:
-> Я пытался приостановить поток между этими двумя строками кода с помощью:
Однако это не работает. Может быть, мне нужно приостановить процесс, а не поток?
Я также пытался (но это не работает):
Как я могу приостановить / спать поток или процесс?
Одним из решений этой проблемы является использование метода Handler.postDelayed () . Некоторые учебные материалы Google предлагают такое же решение.
Однако некоторые отмечают, что приведенное выше решение вызывает утечку памяти, поскольку оно использует нестатический внутренний и анонимный класс, который неявно содержит ссылку на свой внешний класс, активность. Это проблема, когда контекст активности собирается мусором.
Более сложное решение , которое позволяет избежать утечек памяти подкласса Handler и Runnable со статическими внутренними классами внутри деятельности , так как статические внутренних классы не занимающим неявную ссылки на их внешний класс:
Обратите внимание, что Runnable используется WeakReference для Activity, что необходимо в статическом классе, которому требуется доступ к пользовательскому интерфейсу.
Источник
Остановить Thread
Гуру, помогите кодом!
Есть активити, которое заполняется из потока
Поток «линейный»:
-долго думаем — выводим в поле 1
-долго думаем — выводим в поле 2
-долго думаем — выводим в поле 3
(полей много — текст, картинки)
Пользователь может в любой момент нажать «выход» и закрыть активити!
Но поток не умирает сам и пытается вывести очередное поле в уже не существующую активити! (естественно с ошибкой)
Как НАГЛО убить поток?
t.stop(); и t.destroy(); вылетают с ошибкой! (java.lang.UnsupportedOperationException)
Не охота вставлять «переключатель» и проверять его состояние перед любым выводом (полей много и их количество еще растет). Как и оборачивать любое изменение активити в try<. Есть ли "универсальное" решение?
Передать данные в работающий thread из другого thread
Есть 2 потока запущенные разными классами и из потока А нужно сообщить потоку Б что бы он запустил.
Остановить цикл while
Подскажите пожалуйста, не могу понять как остановить цикл while , создал массив из 5 ячеек с Random.
использование thread
при нажатии должен срабатывать episodes и появляться новый layout поверх имеющегося. @Override.
Thread.sleep()
Вообщем, проблемма вот в чем. Я пытаюсь заставить «заснуть» программу, в результате — она засыпает.
Решение
действительно продолжает!
математика планируется сложная, поэтому решил сначала сделать «каркас» потока!
Примерно так (имена заменены/упрощены):
Успешно останавливало поток на очередной «ошибке»
После interrupt() попытался снять try — ошибки после убивания активити не выскакивают, но лог продолжает выводить
111
222
333
(и так до последней)
похоже прийдется делать РУЧНОЙ «обрыватель».
А кто может гарантировать что еще не нул, а когда надумаем вставлять — окажется нул? Мой брейк на try это автоматически проверяет.
Опять-же я мечтал просто вызывать что-то вроде делфийского terminate — и знать что поток в ту-же секунду сдыхает! Даже на середине процесса выполнения команды.
Сейчас засорил поток десятками проверок — маркеры — needBreake, try. cath. Каша вместо кода.
Это если вам ЦИКЛ в потоке нужен! С маленькими «вполне безопасными блоками».
А у меня «линейка»!
Отображаю активити! Надо БЫСТРО его вывести, а потом «дозаполнить» сложными запросами в базы и прогонкой по формулам. Если все это вставить в OnCreate, то получу открытие окна на 5-15 секунд. Причем много полей «не обязательные». Поэтому в OnCreate запускаю поток на «дозаполнение». И в нем расчитываю и вывожу «долгие поля». В любую секунду юзвер может закрыть активити (ему и первых данных хватило или вообще не туда зашел) и нужно прервать поток, а не продолжать считать «в памяти» еще 15 секунд. И не должно выпадать ошибка при выводе «дорасчитанного» еще одного поля в уже несуществующее окно.
Короче. тему можно закрывать! Увы! Пришлось сильно засорить код. Погуглил на других форумах — похоже и с этим ява накосячила. Надеялся что гугл это исправил — тоже не нашел.
Источник
Android лучший и безопасный способ остановить поток
Я хочу знать, что это лучший способ остановить поток в Android. Я знаю, что вместо него можно использовать AsyncTask и что метод cancel() . Я должен использовать Threads в своей ситуации. Вот как я использую thread:
Итак, у кого-нибудь есть идея, которая является лучшим способом остановить поток?
Вы должны сделать прерывания поддержки потоков. В принципе, вы можете вызвать yourThread.interrupt() чтобы остановить поток, и в вашем методе run () вам нужно периодически проверять состояние Thread.interrupted()
Здесь есть хороший учебник.
Эта ситуация ничем не отличается от стандартной Java. Вы можете использовать стандартный способ остановки потока:
Основная идея – время от времени проверять значение поля. Когда вам нужно остановить поток, вы установите значение false. Кроме того, как отметил Крис, вы можете использовать механизм прерывания.
Кстати, когда вы используете AsyncTask, ваш apporach не будет сильно отличаться. Единственное различие заключается в том, что вам придется вызывать isCancel() из вашей задачи вместо специального поля. Если вы вызываете cancel(true) , но не реализуете этот механизм, поток все равно не остановится сам по себе, он будет работать до конца.
На Android такие же правила применяются, как и в обычной среде Java. В Java нити не убиты, но остановка потока выполняется в кооперативном режиме . Поток просят завершить, и поток может затем закончить работу.
Часто используется volatile boolean поле, которое поток периодически проверяет и завершает, когда оно установлено на соответствующее значение.
Я бы не использовал boolean для проверки завершения потока. Если вы используете volatile в качестве модификатора поля, это будет работать надежно, но если ваш код станет более сложным, вместо использования других методов блокировки внутри цикла while может случиться так, что ваш код не завершится вообще или, по крайней мере, займет больше времени Как вы, возможно, захотите.
Некоторые блокирующие библиотечные методы поддерживают прерывание.
Каждый поток имеет уже булевский флаг, и вы должны его использовать. Он может быть реализован следующим образом:
Исходный код, взятый из Java Concurrency на практике . Поскольку метод cancel() является общедоступным, вы можете позволить другому потоку вызывать этот метод по своему усмотрению.
Также interrupted слабо названный статический метод, который очищает прерванный статус текущего потока.
Метод Thread.stop() который может использоваться для остановки потока, устарел; Для получения дополнительной информации см. Почему Thread.stop, Thread.suspend и Thread.resume устарели? ,
Лучше всего иметь переменную, с которой сам поток справляется, и добровольно выходит, если переменная равна определенному значению. Затем вы будете манипулировать переменной внутри своего кода, когда хотите, чтобы поток вышел. Альтернативно, конечно, вы можете использовать AsyncTask .
В настоящее время и, к сожалению, мы не можем ничего сделать, чтобы остановить поток ….
Добавляя что-то к ответу Мэтта, мы можем вызвать interrupt() но это не останавливает поток … Просто сообщает системе остановить поток, когда система хочет убить некоторые потоки. Отдых выполняется системой, и мы можем проверить его, вызвав interrupted() .
[Ps: Если вы действительно собираетесь с interrupt() я прошу вас сделать некоторые эксперименты с коротким сном после вызова interrupt() ]
Дело в том, что вам нужно проверить, что нить работает или нет ? Поле:
Если вы хотите остановить поток, вы должны сделать следующее поле
Внутри любого класса Activity вы создаете метод, который присваивает NULL экземпляру потока, который может использоваться как альтернатива методу амортизации stop () для остановки выполнения потока:
Источник