- Потоки
- Использование фоновых потоков
- Плохое приложение
- Запуск потока
- Усыпить поток
- Приоритет потоков
- Отмена выполнения потока
- Урок 4. Kotlin. Обработка нажатия кнопок и взаимодействие с view в android
- Продолжаем курс по разработке андроид-приложений на языке Kotlin для начинающих программистов.
- Автоматический импорт
- Отображение сообщения по нажатию кнопки
- Working with Countdown Timer in Android Studio Using Kotlin
- What is a countdown?
- How to implement the countdown timer from scratch using Kotlin on Android Studio
- 1. Start a new project on Android studio
- 2. Configure your Project
- 3. Lets design our view
- 5. Kotlin code for the Countdown Timer
- Урок 6. AndroidDev на Kotlin. Activity Lifecycle. Интерфейс LifecycleObserver
- Технологии и инструменты, используемые в уроке:
- Создаем приложение в Android Studio
- Схема Lifecycle
- Функции обратного вызова жизненного цикла активити
- onCreate()
Потоки
Потоки позволяют выполнять несколько задач одновременно, не мешая друг другу, что даёт возможность эффективно использовать системные ресурсы. Потоки используются в тех случаях, когда одно долгоиграющее действие не должно мешать другим действиям. Например, у нас есть музыкальный проигрыватель с кнопками воспроизведения и паузы. Если вы нажимаете кнопку воспроизведения и у вас запускается музыкальный файл в отдельном потоке, то вы не можете нажать на кнопку паузы, пока файл не воспроизведётся полностью. С помощью потоков вы можете обойти данное ограничение.
Использование фоновых потоков
Чтобы быть уверенным, что ваше приложение не теряет отзывчивости, хорошим решением станет перемещение всех медленных, трудоёмких операций из главного потока приложения в дочерний.
Применение фоновых потоков — необходимое условие, если вы хотите избежать появления диалогового окна для принудительного закрытия приложения. Когда активность в 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(), но использовать его не рекомендуется, поскольку он оставляет приложение в неопределённом состоянии. Обычно используют такой подход:
Существует и другой способ, когда все запускаемые потоки объявляются демонами. В этом случае все запущенные потоки будут автоматически завершены при завершении основного потока приложения:
Источник
Урок 4. Kotlin. Обработка нажатия кнопок и взаимодействие с view в android
Продолжаем курс по разработке андроид-приложений на языке Kotlin для начинающих программистов.
На прошлом уроке мы добавили кнопки на главном экране вашего приложения, но пока эти кнопки ничего не делают. В этом уроке сделаем так, чтобы кнопки реагировали, когда пользователь нажимает их.
Автоматический импорт
Перед добавлением поведения к кнопкам необходимо включить автоматический импорт, чтобы Android Studio автоматически импортировала все классы, необходимые для кода Котлин.
- В Android Studio откройте Редактор настроек. Перейдите к File >Other Settings >Default Settings.
- Выберите Auto Imports. В разделе Java убедитесь, что пункт Add Unambiguous Imports on the fly отмечен флажком.
- Закройте редактор настроек.
Отображение сообщения по нажатию кнопки
На этом шаге мы добавим функцию отображения тоста – короткого сообщения на экране. Функция будет выполняться при нажатии кнопки с надписью TOAST.
- Откройте класс MainActivity.kt. (раскройте ветвь app >java >com.example.android.myfirstapp чтобы найти MainActivity). Этот класс описывает поведение главного экрана нашего приложения.Пока что класс содержит только одну функцию, onCreate(). Функция onCreate() выполняется, когда активити стартует.
- Посмотрите внимательно на функцию onCreate(). Обратите внимание на вызов функции setContentView(). Эта строка устанавливает файл ресурсов activity_main.xml в качестве разметки активити главного экрана.
- Добавим новую функцию toastMe() в класс MainActivity. Функция toastMe() принимает один аргумент — View. Это представление, получающее событие нажатия кнопки.Функция создает и отображает всплывающее уведомление. Вот ее код:
Источник
Working with Countdown Timer in Android Studio Using Kotlin
Mar 7, 2020 · 6 min read
This tutorial shows you how to implement a countdown timer from scratch using android studio.
Before we dive into the whole technical aspect of this tutorial let’s try and understand what a countdown is or the need for a countdown timer.
What is a countdown?
A countdown is an act of counting down numerals in reverse o rder to zero. We all make use of countdown in our daily lives, is it when you and couple of friends are playing hide-and-seek or when you heat a delicious meal in the microwave or when Lebron James hit a clutch three pointer to win the championship as the clock winds down to 0.
There are lot of examples of times and moment we make use of countdown timers, the famous one we all know is at the launch of a rocket going to space or the countdown to a new year .
So we can see countdown timers are really important. Let get down to coding shall we.
How to implement the countdown timer from scratch using Kotlin on Android Studio
Before going ahead with this tutorial I’m assuming you having basic understanding of Kotlin programming and android studio.
Lets get to work!
1. Start a new project on Android studio
Select the empty activity so we would be able to create our own views
2. Configure your Project
You can name your app whatever like, i would be using CountdownApp
3. Lets design our view
Android development make use of the XML coding to design views for android apps.
So we are making use of the constraintlayout an EditText which takes our input, A TextView to display the progress of our timer and 2 Button to pause and cancel our Timer. Our second button is invisible because we want to only show that button whenever the timer is paused.
Now our app looks like this
5. Kotlin code for the Countdown Timer
Explanation of code
The Countdown timer package in android takes in time in milliseconds, so we had to convert our time to milliseconds and 1 minute equal to 60000 milliseconds.
start_mili_seconds initializes our timer text to start countdown from one minute in the absent of an inputted minute. The is_running variable helps us check if our timer is running so we are able to change the button text and also make the reset button visible whenever the is_running variable is true.
On click of the button that triggers the timer, we check if is_running is true we run the pauseTimer() function which changes the button text to pause and makes the reset button visible and also pause the timer, or else it takes the text from the EditText and converts it to a milliseconds and pass it as a parameter to the startTimer() function which then start our timer.
The startTimer() function consist of the whole logic we need to start our countdown, first we create a global variable:
which makes out CountDownTimer class available where we need it, now we need to initialize the countdown_timer
we make use of object declaration to initialize our CountDownTimer class which takes in 2 arguments:
- The time you intend to countdown in seconds and for us we named it as time_in_seconds
- The amount of time reduced in seconds, here we are using 1000 that’s per milliseconds reduce the time_in_seconds
It has two (2) implemented methods which are the onTick() and onFinish()
The onTick updates our UI text ( Textview) on the time remaining for the countdown to reach zero.
The updateTextUI() function converts our time_in_milliseconds and display it in actual minute and seconds so the user is able to understand and monitor the countdown timer.
Once the countdown is finished the onFinish() loads a confetti function which displays konfetti around the screen for successful completion of the countdown
To be able to use the Konfetti in your app you need to add this to your build.gradle file
and also add this to your MainActivity.kt file
Now that we have our countdown and konfetti. we want to be able to reset our timer when we want and that’s why we have the resetTimer() function
This function resets our timer back to 0 and hides the reset button so we start the timer all over again.
Источник
Урок 6. AndroidDev на Kotlin. Activity Lifecycle. Интерфейс LifecycleObserver
Продолжаем курс по обучению основам разработки мобильных приложений в Android Studio на языке Kotlin.
Это урок 6, в котором мы познакомимся с событиями и состояниями жизненного цикла Активити, а также поговорим о том, как их нужно (и как не нужно) обрабатывать в процессе разработки приложения.
Предыдущий урок, на котором мы добавляли второй экран в андроид-приложение, здесь
Технологии и инструменты, используемые в уроке:
Как вы уже знаете из прошлых уроков, Активити — это, по сути, экран нашего приложения. Каждый пользователь андроид устройства запускает, сворачивает экраны приложения, запускает другие приложения, вертит устройство в руках. Что происходит при этом с активити? Как изменяются его состояния? И главный вопрос, как разработчик приложения должен это учитывать? Сейчас мы это выясним.
Создаем приложение в Android Studio
Давайте создадим приложение и на его примере будем изучать поведение активити.
Каждый раз при создании нового приложения по умолчанию создается класс главного экрана приложения — MainActivity.
Когда пользователь нажимает ярлык приложения, система запускает активити, которое указано как стартовое в манифесте приложения. По умолчанию это MainActivity. После запуска мы видим активити на экране. Мы можем свернуть его или открыть другое приложение, экран настроек и т.д. При этом наше активити уходит на второй план и перестает быть видимым. Однако оно не уничтожается, а продолжает работать в фоне, и мы можем в любой момент к нему вернуться. Наконец, мы можем совсем закрыть приложение, или его может закрыть система, если ей будет не хватать оперативной памяти. Тогда активити прекратит свою работу и будет уничтожено.
Кроме того, активити может пересоздаваться — уничтожаться и создаваться заново. Это происходит при событиях изменения конфигурации, таких как поворот устройства из портретной ориентации в альбомную (и обратно), смена размера экрана или языка интерфейса. О смене конфигурации мы более подробно поговорим на следующем уроке.
Схема Lifecycle
А сейчас посмотрите на схему состояний, через которое проходит активити в процессе работы, и событий, которые при этом происходят. Схема с официального сайта https://developer.android.com/images/topic/libraries/architecture/lifecycle-states.png
В прямоугольниках указаны состояния (states) активити. А события (events), которые происходят при смене состояний, отмечены стрелками. Важно понимать, что не события управляют состояниями активити, скорее наоборот. Состояния активити изменяются системой Андроид, а события происходят в процессе изменения.
Когда активити запускается системой, оно инициализируется (INITIALIZED) и происходит событие ON_CREATE. При этом активити переходит к состоянию “создано” (CREATED).В этот момент должен инициализироваться пользовательский интерфейс, поскольку активити готовится отобразиться пользователю. Далее происходит событие ON_START и активити переходит к состоянию “запущено” (STARTED). Следующее событие ON_RESUME. Активити переходит в состояние — RESUMED (возобновлено) — выходит на передний план, получает фокус и отображается пользователю. Если активити в процессе работы теряет фокус и частично перекрывается, например, диалоговым окном или другим активити, то переходит обратно в состояние STARTED. При этом происходит событие ON_PAUSE. В этом состоянии активити приостанавливается, но может быть все еще видимым на экране, например, в многооконном режиме. Если же активити полностью перекрыто, то система его останавливает и переводит в состояние CREATED. Выполняется событие ON_STOP. Активити пока не уничтожается системой и может в любой момент возобновить работу. Но поскольку оно не видно пользователю, то в этом состоянии целесообразно отключать некоторые функции, например, воспроизведение анимации. Если пользователь закрыл активити или система испытывает недостаток памяти, или изменилась конфигурация устройства (произошел поворот), активити уничтожается системой. При этом происходит событие ON_DESTROY. В этот момент необходимо освобождать ресурсы, используемые активити.
Функции обратного вызова жизненного цикла активити
На рассмотренной нами схеме указаны события жизненного цикла, всего их шесть: ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP и ON_DESTROY..
Для обработки событий класс Activity имеет колбеки — функции обратного вызова, соответствующие каждому событию жизненного цикла. Например, это уже известная вам функция onCreate(savedInstanceState: Bundle?) <…>в которой происходит инициализация пользовательского интерфейса и вызовы некоторых других функций.
Но кроме одноименных функций жизненного цикла, в активити есть несколько дополнительных, таких как onPostResume() и onRestart(). Мы их будем использовать в качестве вспомогательных для большей наглядности.
Во всех функциях обратного вызова нужно переопределять одноименные методы суперкласса во избежание ошибок.
Функции обратного вызова полезны для изучения жизненного цикла. До недавнего времени они массово использовались разработчиками для управления поведением приложения. Однако сейчас Гугл рекомендует другой, более правильный подход, который мы рассмотрим далее в этом уроке. А пока переопределим эти функции в активити.
onCreate()
Первая функция, которая переопределена по умолчанию в каждом активити, отвечает событию ON_CREATE. Выполняется перед стартом активити, когда активити переходит из состояния INITIALIZED к состоянию CREATED.
В теле функции onCreate должна выполняться базовая логика приложения, например связывание данных со списками, инициализация переменных и т.д.
Источник