- Класс Handler
- Периодическое выполнение задачи
- Пример с индикатором прогресса
- Splash-screen
- Русские Блоги
- Подробное использование Android Handler
- Зачем вам нужен Handler?
- Дочерним потокам не разрешен доступ к пользовательскому интерфейсу
- Знакомство с обработчиком
- Использование обработчика
- Метод 1: публикация (запускается)
- Метод 2: sendMessage (сообщение)
- Проблемы с обработчиком
- Аспект памяти
- Аномальный аспект
- избегать
- Улучшения обработчика
- Реализация обработчика
- Метод 1. Реализуйте исполняемый интерфейс, общайтесь через публикацию (Runnable) и уведомляйте об обновлениях Activity через данный интерфейс обратного вызова
- Метод 2: наследовать поток, общаться через sendMessage обработчика
- Механизм связи обработчика
- Как Handler связывает Looper и MessageQueue
- 1. Обработчик отправляет сообщения
- 2. Сообщение попадает в очередь.
- 3. Looper обрабатывает сообщения
- 4. Обработчик обрабатывает сообщение.
- подводить итоги
- Интеллектуальная рекомендация
- Многослойная презентацияViewController Jap
- Распечатать список с конца до головы
- Типы данных и переменные
- Python Daily Practice (4) -идиомы заполняют музыку
- Полный список
Класс Handler
Класс android.os.Handler является дальнейшим развитием потоков, упрощающий код. Handler может использоваться для планирования выполнения кода в некоторый момент в будущем. Также класс может использоваться для передачи кода, который должен выполняться в другом программном потоке.
Рассмотрим максимально простой пример для знакомства
Запустите пример на эмуляторе и через некоторое время закройте его через кнопку Назад или Домой. При этом смотрите на логи на вкладе Android Monitor. Вы увидите, что приложение по-прежнему печатает текст типа после секундной задержки после запуска.
Разберёмся, что происходит и как следует читать код.
Мы объявили новый объект Handler и булевую переменную, которая по умолчанию имеет значение false — по ней будем отслеживать состояние приложения. В третьей переменной мы сохраним текущее время в момент запуска.
Приложение запустилось, сразу же запоминаем время через currentTimeMillis() — это опорная точка отсчёта.
Основная логика заключена в условии if — тут пишется то, что мы хотим поместить в новый поток. Не страшно, если не понятно, как это всё работает. Просто уясните принцип. Мы иницилизируем объект mHandler и сразу начинаем его настраивать. Переопредляем его главный метод handleMessage() и вызываем метод суперкласса. Это ничем не отличается от вызова onCreate() активности, мы не раз такое делали.
Блок if позволяет управлять кодом для потока. Сам запуск мы сделаем позже. А в самом блоке мы снова получаем текущее время и сравниваем с самой первым временем, полученным во время запуска. Для удобства вычисления идут в секундах. Результат выводится в лог. Метод sendEmptyMessageDelayed() сообщает системе, что мы хотим повторять код в handleMessage() раз в секунду.
После инициализации и настройки mHandler мы присваиваем значение true переменной gameOn, показывая готовность к запуску кода из блока if.
Последняя строка sendEmptyMessage() запускает поток.
Можно использовать более сложные приёмы запуска потока, но пока этого достаточно для понимания.
Периодическое выполнение задачи
При сложных вычислениях может понадобиться очередь Runnable-объектов. Помещая объект в очередь, вы можете задать время его запуска. Для демонстрации использования обработчика потока напишем программу, запускающую фоновый процесс, который будет каждые 200 миллисекунд получать текущее время и обновлять текст. Нам понадобится кнопка Пуск и две текстовые метки, в которых будет отображаться время и количество нажатий кнопки:
На экране будет отображаться время и одновременно мы можем нажимать на кнопку. Эти действия не мешают друг другу, так как работают в разных потоках.
Кроме метода postDelayed() вы можете использовать метод postAtTime():
В этом случае объект r добавляется в очередь сообщений, запуск объекта производится во время, заданное вторым параметром.
Самый простой способ помещения объекта в очередь — метод post(), когда указывается только помещаемый объект без указания времени выполнения объекта:
Пример с индикатором прогресса
Всё, что вам нужно — создать экземпляр класса Handler в классе активности. Поток будет работать с объектом Handler, который в свою очередь, будет обновлять шкалу индикатора в основном потоке активности.
Чтобы послать сообщение в объект Handler, сначала необходимо вызвать метод obtainMessage(), чтобы извлечь объект Message из глобального пула сообщений.
Для вставки сообщения в очередь сообщений объекта Handler существует несколько методов:
- sendMessage() — помещает сообщение в очередь немедленно (в конец очереди)
- sendMessageAtFrontofQueue() — помещает сообщение в очередь немедленно и, кроме того, помещает это сообщение впереди очереди (по умолчанию оно ставится в конец очереди), таким образом ваше сообщение берет приоритет над всеми другими
- sendMessageAtTime() — помещает сообщение в очередь в установленное время в миллисекундах
- sendMessageDeiayed() — помещает сообщение в очередь после задержки, выраженной в миллисекундах
Чтобы обрабатывать эти сообщения, для объекта Handler необходимо реализовать метод обратного вызова handleMessage(), который будет вызываться каждым сообщением из очереди сообщения.
Для примера создадим приложение с ProgressBar, который будет отображать ход выполнения длительной задачи (это будет простой цикл с приостановкой потока на 1 секунду в каждой итерации цикла) и обновлять степень завершения этой задачи через объект Handler в классе активности.
Splash-screen
Очень часто программисты используют Handler для реализации окна приветствия, которое автоматически закрывается и следом запускается основная активность игры или приложения.
Источник
Русские Блоги
Подробное использование Android Handler
Handler: Это объект распространения сообщений для отправки и обработки сообщений, и его объект Runnable связан с MessageQueue потока.
эффект: Планирование сообщений, переключение задачи на указанный поток для выполнения.
Зачем вам нужен Handler?
Дочерним потокам не разрешен доступ к пользовательскому интерфейсу
Если дочернему потоку разрешен доступ к пользовательскому интерфейсу, элементы управления пользовательского интерфейса будут в неожиданном состоянии в случае одновременного доступа нескольких потоков.
Традиционное решение: блокировка, но это усложнит логику доступа к UI, а во-вторых, снизит эффективность доступа к UI.
Знакомство с обработчиком
Однопоточная модель используется для обработки операций пользовательского интерфейса, а обработчик переключается на поток пользовательского интерфейса для решения проблемы недоступности пользовательского интерфейса в дочернем потоке.
Использование обработчика
Метод 1: публикация (запускается)
Создайте рабочий поток, реализуйте интерфейс Runnable, реализуйте метод запуска и обработайте трудоемкие операции.
Создайте обработчик, опубликуйте созданный Runnable через handler.post/postDelay и обновите пользовательский интерфейс в методе run.
Метод 2: sendMessage (сообщение)
Создать рабочий поток, унаследовать поток, перезапустить метод запуска и обработать трудоемкие операции
Создайте объект сообщения, установите флаг what и данные
Доставить сообщения через sendMessage
Создайте обработчик, перепишите метод handleMessage, оцените в соответствии с информацией msg.what, получите соответствующую информацию и обновите пользовательский интерфейс здесь.
Проблемы с обработчиком
Аспект памяти
Обработчик называется Activity, если это нестатический внутренний класс, он будет ссылаться на объект внешнего класса. Когда действие завершается, обработчик может не завершить выполнение, что вызывает утечку памяти в действии. Следовательно, статические внутренние классы используются везде, где вызывается Handler.
Аномальный аспект
Когда действие завершается, некоторые ресурсы освобождаются в методе onDestroy. В это время Handler выполняет метод handlerMessage, но связанные ресурсы были освобождены, что вызывает исключение нулевого указателя.
избегать
Если вы используете handlerMessage, добавьте в метод try catch.
Если вы используете метод post, добавьте try catch в метод Runnable.
Улучшения обработчика
Аспект памяти: используйте статический внутренний класс для создания объекта-обработчика и удерживайте слабую ссылку на Activity
Аспект исключения: вместо добавления try catch сообщение в очереди сообщений MessageQueue удаляется в onDestory.
Затем используйте следующий метод для создания объекта-обработчика:
И уничтожить в onDesotry:
Реализация обработчика
Длительная операция предполагает загрузку изображения из сети
Поток, который наследует Thread или реализует интерфейс Runnable, отделен от потока пользовательского интерфейса. Runnable взаимодействует с основным потоком через интерфейс обратного вызова, чтобы уменьшить связь и улучшить возможность повторного использования кода.
Создайте объект-обработчик в Activity и вызовите рабочий поток для выполнения
Метод 1. Реализуйте исполняемый интерфейс, общайтесь через публикацию (Runnable) и уведомляйте об обновлениях Activity через данный интерфейс обратного вызова
Метод 2: наследовать поток, общаться через sendMessage обработчика
Механизм связи обработчика
- Создайте Handler и используйте Looper текущего потока для создания системы цикла сообщений;
- Обработчик отправляет сообщения через sendMessage (Message) или Post (Runnable) и вызывает enqueueMessage, чтобы вставить сообщение в список сообщений;
- Looper циклически обнаруживает сообщения в очереди сообщений, если есть сообщение, он извлекает сообщение и вызывает метод dispatchMessage обработчика, содержащегося в сообщении, и вызывает для исполнения handleMessage, перезаписанный в потоке Handler.
Как Handler связывает Looper и MessageQueue
1. Обработчик отправляет сообщения
Знакомый код из предыдущего абзаца:
Начать отслеживание с sendMessageQueue, связь вызова функции: sendMessage -> sendMessageDelayed -> sendMessageAtTime, в sendMessageAtTime сообщение, отправленное перевозчиком, и mQueue обработчика попадают в очередь вместе через enqueueMessage.
Для postRunnable runnable доставляется через post, вызывается getPostMessage, сообщение создается через runnable, а затем доставляется через sendMessageDelayed, а затем процесс такой же, как процесс sendMessage.
2. Сообщение попадает в очередь.
В enqueueMessage войдите в очередь через MessageQueue и назначьте цель сообщения текущему объекту-обработчику. Помните, что msg.target очень важен. После того, как Looper извлекает сообщение, его необходимо вызвать обработчику с помощью msg.target.dispatchMessage Обработайте сообщение.
В MessageQueue список сообщений Message помещен в очередь
3. Looper обрабатывает сообщения
Прежде чем говорить об обработке сообщений, давайте посмотрим, как создается и получается Looper:
- При создании Looper создайте очередь цикла сообщений и получите текущий поток
- Но эта функция является частной, и внешний мир не может напрямую создать Looper, но создается Looper.prepare:
- Создайте здесь Looper и сохраните объект Looper в sThreadLocal. Что такое sThreadLocal?
Это экземпляр TheadLocal, который сохраняет Looper, а ThreadLocal — это класс хранения частных данных потока, который может сохранять объект Looper потока, так что Handler может сохранять объект Looper через ThreadLocal.
- Как TheadLocal сохраняет и получает Looper?
В наборе экземпляр Looper текущего потока сохраняется через values.put и получается через values.getAfterMiss (this), где put и getAfterMiss имеют ключ и значение, которые сохраняются в массиве таблиц объекта Value, затем в массиве таблиц Как это хранится?
Очевидно, что в массиве первый содержит индекс, на который ссылается объект ThreadLocal, а последний хранит переданный экземпляр Looper.
- Затем давайте посмотрим, как Looper обрабатывает сообщения в цикле.
В цикле, цикл, сообщение в MessageQueue выводится через следующий
Если полученное сообщение пустое, завершите цикл и вернитесь.
Установите сообщение как пустое, вы можете уведомить очередь сообщений о выходе с помощью методов quit и quitSafely MessageQueue.
Если полученное сообщение не пустое, оно обратится к обработчику через msg.target.dispatchMessage.
4. Обработчик обрабатывает сообщение.
Looper возвращает сообщение в dispatchMessage обработчика для обработки сообщения:
Если сообщение имеет обратный вызов, сообщение доставляется с помощью Post (Runnable), потому что, когда запускаемый объект доставляется, запускаемый объект назначается обратному вызову сообщения.
Если mCallback обработчика не пуст, он будет обработан путем создания обработчика посредством обратного вызова.
В противном случае наиболее распространенным способом создания объектов-обработчиков является переопределение handlerMessage.
подводить итоги
Диаграмма последовательности используется для обобщения механизма сообщений обработчика, включая описанный выше процесс связывания Looper и MessageQueue.
Автор: Zero SOUL
Ссылка: https://www.jianshu.com/p/0a274564a4b1
Источник: Краткая книга
Интеллектуальная рекомендация
Многослойная презентацияViewController Jap
. Недавно, проект использует многоэтажные прыжки [A presentViewController: B animated: YES] [B presentViewController: C animated: YES] . Проблема в том, где: как это идет прямо к? Я не нашел ме.
Распечатать список с конца до головы
В случае, когда таблица цепи не может изменять дисплей, данные хранения стека могут рассматриваться с рекурсивным методом. Разрешить модификацию структуры ссылки.
Типы данных и переменные
тип данных Компьютерная программа может обрабатывать различные значения. Однако компьютеры могут обрабатывать гораздо больше, чем числовые значения. Они также могут обрабатывать различные данные, таки.
Python Daily Practice (4) -идиомы заполняют музыку
оглавление 1. Одно место 2. Случайное расположение 3. Добавьте баллы для оценки 4. Получение файла 5. Установите уровень сложности. 6. Срок завершения 7. Выберите заполнение пропусков. 1. Одно место Н.
Источник
Полный список
— посылаем отложенные сообщения
— удаляем сообщения из очереди
— используем Handler.Callback для обработки сообщений
В прошлых уроках мы отправляли сообщения в очередь, а система сразу же доставала их и перенаправляла в Handler на обработку. Но мы можем настроить сообщение так, чтобы система отправило его на обработку не сразу, а с задержкой. Для этого используются методы sendEmptyMessageDelayed (если используете только what) и sendMessageDelayed (полное сообщение). В них мы можем указать паузу в миллисекундах. Система выждет эту паузу и только потом отправит сообщение в Handler.
Если вдруг поместили такое отложенное сообщение в очередь, а потом решили, что оно не должно уйти на обработку, то его можно из очереди удалить. Для этого используется метод removeMessages.
В прошлых уроках мы создавали свой Handler, и в его методе handleMessage кодили свой алгоритм обработки сообщений. Кроме этого способа Handler также может использовать для обработки сообщений объект, реализующий интерфейс Handler.Callback. У интерфейса всего один метод handleMessage – в нем и прописываем всю логику обработки сообщений. Я пока не встречал практической пользы от этой штуки, но все же разберемся, как ее можно использовать. Может когда и пригодится.
Project name: P0831_HandlerMessageManage
Build Target: Android 2.3.3
Application name: HandlerMessageManage
Package name: ru.startandroid.develop.p0831handlermessagemanage
Create Activity: MainActivity
strings.xml и main.xml не трогаем, они нам не нужны. Будем работать с логами.
Мы создаем объект hc типа Handler.Callback. У него есть метод handleMessage, в котором мы будем обрабатывать сообщения. В нашем случае просто читаем атрибут what и выводим значение в лог.
В onCreate создаем handler, используя конструктор Handler (Handler.Callback callback). На вход передаем созданный ранее hc. И теперь Handler будет обрабатывать сообщения не сам, а перепоручит это объекту hc. Далее мы выполняем метод sendMessages , который кладет три сообщения в очередь сообщений. Для этого используется метод sendEmptyMessageDelayed. Это аналог знакомого нам метода sendEmptyMessage с прошлого урока. Он тоже заполняет в сообщении только атрибут what, но при этом он позволяет указать задержку в обработке сообщения. Т.е. сообщение будет извлечено из очереди и отправлено на обработку через указанное количество миллисекунд.
Итак, мы помещаем три сообщения:
1) what = 1, обработка через 1000 мс.
2) what = 2, обработка через 2000 мс.
3) what = 3, обработка через 3000 мс.
Замечу, что отсчет задержки начинается после помещения в очередь, а не после обработки предыдущего сообщения. Т.е. эти сообщения по отношению друг к другу сработают с интервалом в одну секунду.
Все сохраним и запустим приложение. В логе одна за другой будут появляться записи:
10:21:07.759: D/myLogs(332): send messages
10:21:08.786: D/myLogs(332): what = 1
10:21:09.765: D/myLogs(332): what = 2
10:21:10.776: D/myLogs(332): what = 3
Обратите внимание на время этих записей. Первое срабатывает через 1000 мс после помещения в очередь (send messages), второе — через две секунды, третье – через три.
Теперь попробуем удалить сообщение из очереди. Перепишем метод sendMessages:
Используем метод removeMessages, в котором указываем значение атрибута what. Этот метод находит в очереди сообщение с атрибутом what, равным 2, и удаляет его из очереди.
Все сохраняем, запускаем приложение. Смотрим лог:
10:24:49.916: D/myLogs(434): send messages
10:24:50.927: D/myLogs(434): what = 1
10:24:52.948: D/myLogs(434): what = 3
Как видим, сообщение с what = 2 не сработало.
А если будет несколько сообщений с одинаковым значением what? Система удалит первое попавшееся или все?
Проверим. Перепишем sendMessages:
Будем помещать в очередь кучу сообщений. Из них несколько с what = 2. Проверим, какие удалит система.
Запускаем приложение и смотрим лог:
10:29:23.297: D/myLogs(467): send messages
10:29:24.372: D/myLogs(467): what = 1
10:29:26.307: D/myLogs(467): what = 3
10:29:28.364: D/myLogs(467): what = 5
10:29:30.332: D/myLogs(467): what = 7
Все сообщения с what = 2 были удалены. Не забывайте это. А то захотите удалить одно последнее сообщение, а система найдет все подходящие, ожидающие обработки, и снесет их.
У метода removeMessages есть еще реализация с использованием obj. Тут все так же, только система ищет для удаления из очереди сообщения с указанными атрибутами what и obj.
Если хотите запланировать полноценное сообщение, а не просто what, то используйте метод sendMessageDelayed – на вход даете сообщение и указываете задержку обработки.
Есть еще методы sendEmptyMessageAtTime и sendMessageAtTime. Они тоже позволяют указать задержку обработки. Но эта задержка будет отсчитана от времени последнего старта системы, а не от времени помещения в очередь. Если сообщение окажется просроченным на момент помещения в очередь, оно выполняется сразу.
На следующем уроке:
— работаем с Handler и Runnable
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник