Разное
DialerLoading: A Rotary Dialer loading for Android — набор номера телефона старым дедовским способом
ldoublem/PaperShredder: a PaperShredder view for android — анимация шредера
Библиотека Android-WScratchView — стираем защитный слой у скретч-карт
shchurov/HorizontalWheelView — колёсико для выбора значений.
frakbot/JumpingBeans — прыгающие слова.
robinhood/ticker: An Android text view with scrolling text change animation — анимация текста как у счётчиков.
renaudcerrato/DoorSignView: Customizable, sensor-enabled, door sign custom views for Android — табличка на дверь, в том числе и анимированная.
Android Holo ColorPicker
Библиотека Android Holo ColorPicker позволяет выбрать цвет с помощью цветового колеса. Страница проекта
Более свежая библиотека LarsWerkman/Lobsterpicker написана в стиле Material Design.
ParallaxPagerTransformer
Параллакс для ViewPager.
Домашняя страница xgc1986/ParallaxPagerTransformer
Демонстрация (автор библиотеки наш человек)
Создание колбэка для подключения к службе
Чтобы использовать MusicService внутри других классов, нам нужно создать его экземпляр. Откройте MainActivity.kt и добавьте в начало класса следующее:
Здесь мы объявляем переменную, которая содержит экземпляр сервиса. В данный момент сервис является null. Мы назначим новое значение, когда активити подключится к службе с помощью интерфейса Binder. Чтобы уловить изменения состояния соединения, создайте колбэк соединения.
Добавьте код под инициализацией musicService:
Этот блок кода не сложно понять:
- Это колбэк для состояния подключения сервиса.
- Когда активити подключается к сервису, система использует экземпляр MusicBinder и getService() чтобы передать ссылку в musicService.
- Когда сервис отключается, воспроизведение звука прекратится, если ссылка на сервис еще не приняла значение null, при этом ссылка на сервис будет удалена.
Также устанавливается флаг isMusicServiceBound, который проверяет состояние привязки к сервису в обоих методах в соответствии с заданными вами параметрами
Это важно, чтобы избежать исключений DeadObjectException, которые удаленные методы генерируют при разрыве соединения
Привязка к Сервису
Следующим шагом мы создадим привязку сервиса при запуске MainActivity. Найдите onStart() и добавьте:
Здесь вы проверяете, имеет ли сервис уже привязку. Если нет, вы вызываете метод привязки.
Метод привязки еще не существует, поэтому добавьте его код ниже onDestroy():
В этом куске кода мы:
- Заявляем о намерении запустить MusicService
- Предоставляем сервису информацию о нашем Intent вместе с колбэком соединения и флагом, который автоматически создает сервис, если привязка существует.
Чтобы избежать утечек памяти или ошибок, вам нужно добавить код для отмены привязки сервиса. Добавьте в unbindMusicService() следующее:
Таким образом, вы говорите сервису выполнить onServiceDisconnected() в колбеке boundServiceConnection.
Межпроцессные взаимодействия
Каждое приложение Android работает в собственном процессе с уникальным идентификатором процесса. Когда вы запускаете приложение, система Android генерирует процесс и выполняет основное действие в основном потоке. Плюс этого в том, что приложение живет в изолированной среде, и другие приложения не могут его прервать.
Исходя из этого, Android позволяет запускать компоненты в другом процессе, который не используется для запуска приложения. Для этого вам нужно использовать тег процесса внутри AndroidManifest.xml. У процесса может быть случайное имя, например myNewProcess.
Многопроцессорность повышает безопасность вашего приложения и улучшает управление памятью. Однако, если вы его используете, вам нужно найти способ взаимодействия между различными процессами.
Вам нужно включить только один программный интерфейс — IBinder, но Android предоставляет три способа его определения:
- Использование AIDL
Первый способ мы уже рассмотрели в этом туториале, но не стесняйтесь изучить и другие.
Объявление сервиса в Manifest
Перед использованием сервиса его необходимо объявить в AndroidManifest.xml. Сервис — это компонент Android, точно так же, как и Activity. Для удобства наш проект уже содержит классы сервисов, но вам все еще необходимо правильно их конфигурировать.
Перейдите к AndroidManifest.xml и добавьте этот код внутрь application:
В этом кода вы можете увидеть следующее:
- Android:name: Имя класса сервиса.
- Android:enabled: Если установлено значение true, система может создавать экземпляры сервисов.
- Android:exported: Если установлено значение False, то системе сообщается, что ни одно другое приложение не может запускать и использовать эти сервисы.
Значение android:name выделиться красным цветом, но пока просто не обращайте на это внимание. Мы починим это чуть позже
А пока начнем работу по реализации нового функционала.
Обновление уведомления при изменении таймера
TimerService содержит сопрограмму, которая тикает каждую секунду во время выполнения уровня. Вы будете использовать значение таймера, чтобы обновить представление уведомлений.
Найдите BroadUpdate () внутри TimerService.kt и добавьте этот код в if:
Вот что делает этот блок кода:
- Здесь вы отправляете трансляцию с истекшим временем в MainActivity. С его помощью MainActivity может обновлять время в TextView.
- Этот вспомогательный метод обновляет уведомление в строке состояния, которое мы сделали ранее.
На этом этапе мы уже сделали все, что видит пользователь во время игры. Но что произойдет, если пользователь закроет приложение во время работы таймера?
Чтобы это работало корректно, добавьте следующую строку в broadcastUpdate() в else if:
Эта строчка обновляет текст уведомления, зазывающего пользователя обратно в игру.
Отличная работа! Запустите проект, чтобы проверить таймер
Запустите игру на каком-нибудь уровне сложности и обратите внимание, как внизу меняется таймер. Потяните вниз строку состояния, чтобы увидеть, как таймер изменяется в уведомлении
Попробуйте выйти из приложения, чтобы проверить обновление текста сообщения в уведомлении.
Определение методов сервисов для управления аудио
Этот сервис позволяет пользователю взаимодействовать со звуковыми иконками для воспроизведения, приостановки, остановки и перемешивания музыки. Для простоты, некоторые методы управления звуком уже определены. Однако сам музыкальный проигрыватель все еще не определен.
Чтобы создать музыкальный проигрыватель, добавьте этот код в initializeMediaPlayer() внутри MusicService.kt:
Здесь вы используете MediaPlayer для запуска непрерывно повторяющегося звука первой песни в randomSongs.
Еще одна интересная особенность такого сервиса заключается в том, что он может предоставить имя воспроизводимого трека. Внутри MusicService добавьте:
В этом методе мы читаем название дорожки из ресурсов и изменяем String, чтобы она была более читаемой для пользователя.
Все сделано! Теперь воспользуемся этими методами из другого компонента.
Реализация интерфейса сервиса
Каждый кастомный класс сервиса должен быть подклассом Service и должен реализовывать и переопределять несколько базовых методов колбэка, связанных с жизненным циклом сервиса.
Вот наиболее важные из них:
- onStartCommand(): вызывается системой, когда другой компонент хочет запустить сервис, использую startService(). Как только система вызывает onStartCommand(), сервис может работать в фоновом режиме столько времени, сколько потребуется для завершения процесса. Вам нужно не забыть остановить службу вручную, когда работа будет завершена, вызвав stopSelf() или topService(). Эта не нужно, если вы хотите просто выполнить привязку к сервису, не запуская его.
- onBind(): Вам всегда нужно применять этот метод колбэка. Система использует этот колбэк при вызове bindService(). Используйте его для привязки другого компонента к сервису. Он открывает возможность коммуникации, таким образом вы предоставляете интерфейс для взаимодействия клиентов возвращая IBinder. Если вы не хотите использовать привязку, просто верните null.
- onCreate(): Используйте этот метод для настройки сервиса перед его запуском. Система вызывает его, только если сервис еще не запущен.
- onDestroy(): Система вызывает его, чтобы уничтожить сервис, когда он больше не нужен. Это последний вызов, который получает сервис. После этого сервис перестает использовать какие-либо ресурсы.
Зачем мы это используем
При разработке приложений, мы часто хотим видеть одинаковую работу нашего кода на разных версиях устройств. Вместо того, чтобы писать код поддержки для ранних версий Андроид, нам достаточно взять готовую реализацию из Support Library и заняться более важными задачами (таски же должен кто-то закрывать).
Однако так было ранее, ведь сейчас, библиотека поддержки это куда больше, чем куча if else с проверкой версионности. Она содержит в себе такие полезные как:
- — отличная альтернатива устаревшему
- — для реализации таб-ориентированной навигации или простого слайдинга
- — позволяющий быстро и просто добавить боковое меню
- — для разнородного контента
И даже помимо этого, в ней содержатся такие замечательные штуки как линтеры, любезно подсказывающие нам вероятные ошибки, различные утилитные классы типа , аннотации и кучу другого. Их использование значительно упрощает жизнь рядовому разработчику.
Объяснение ограничений для фонового выполнения
Android 8 и более новые версии имеют ограничения при использовании Android Services в фоновом потоке:
- Система уничтожит сервис через некоторое время, если приложение запускает его в фоновом режиме. Когда приложение переходит в фоновый режим, у него есть всего лишь несколько минут, в течение которого оно может взаимодействовать с сервисами. После этого система останавливает работу всех запущенных служб.
- Система выдаст исключение, если сервис был запущен, когда приложение находилось в фоновом режиме и за пределами временного окна.
Дополнительные сведения см. В документации по ограничениям фонового выполнения.
Заметка
Из-за всех этих ограничений фоновые сервисы используются крайне редко. Как упоминалось выше, а также рекомендовано , лучшим решением для фоновой работы является использование Work Manager. Подробнее об этом читайте в разделе «Планирование задач с помощью Android WorkManager».
А теперь пора узнать о последнем виде сервисов.
Представляем Android Services
Android Services — это компонент, который помогает выполнять длительные процессы, такие как обновление базы данных или сервера, запуск обратного отсчета или воспроизведение звука. По умолчанию Android Services запускаются в том же потоке, что и основные процессы приложения. Такой вид службы также называют local service.
Ресурсоемкие задачи данный сервис будет выполнять в фоновом режиме. Это позволит пользователю взаимодействовать с приложением. Например, если пользователь захочет позвонить или просмотреть уведомления при обновлении сервера, он сможет сделать это, не прерывая и не отменяя обновления.
Для этого нужно создать фоновый поток и вручную указать, какие задачи должны выполняться именно в этом потоке, поскольку сервисы не поддерживают реализацию потока напрямую.
Поскольку Android Services не имеет пользовательского интерфейса, он никак не зависит от последовательности выполнения других процессов. Это означает, что вы можете запускать его, даже когда пользователь вообще никак не взаимодействует с приложением.
Кроме того, другие компоненты приложения могут взаимодействовать с сервисами или даже осуществлять межпроцессное взаимодействие (InterProcess Communication (IPC)). Если вы будете дальше следовать этому туториалу, то узнаете больше о IPC.
В следующих разделах этого туториала мы применим каждый из перечисленных ниже типов Android Services и добавим в наше приложение Memo много новых функций:
- Foreground service: Добавим сервис TimerService, который содержит логику для отслеживания времени.
- Bound service: Используем MusicService, который позволит нам воспроизводить, ставить на паузу и перемешивать саундтреки.
Давайте начнем!
Как строится нейминг библиотек
можно видеть список всех доступных для подключения библиотек с их кратким описанием.
Большинство библиотек поддержки имеет префикс, который ПО-СЛУХАМ говорит о минимальной версии андроид, необходимой для её работы.
Помимо упомянутых ранее виджетов, библиотека поддержки предоставляет нам улучшенный , библиотеку для работы с цветами, а также для реализации экрана настроек (которой никто не пользуется, кек)
Подключаются они все примерно одинаково:
// v4 compat libraryimplementation 'com.android.support:appcompat:27.1.0'// v7 compat libraryimplementation 'com.android.support:appcompat-v7:27.1.0'
за исключением того, что у библиотек отсутствует префикс)) Добро пожаловать в мир андроид разработки, здесь довольно часто в порядке вещей делать, казалось бы, одну и ту же вещь по разному. Даже гугл не стремается, нам то уж чего.
уже считается довольно устаревшей и по дефолту студия генерирует нам семплы именно с , чего и я советую вам придерживаться.
тянет за собой целый ворох различных зависимостей (даже архитектурных!!, а вы тут всё “какааая архитектура в ондроид”)
их тут действительно много
С одной этой подключенной библиотекой , проект уже использует примерно 30% от всего доступного места (если считать по количеству методов). Ради справедливости стоит отметить, что здесь подключен и Котлин являющийся де-юро (но пока далеко не де-факто) стандартом разработки под Андроид.
состоит из 11.000 методов
и некоторые из этих библиотек мне не нужны, к примеру фрагменты и все её дочерние 13 зависимостей. Вместо них я использую обычные (на примере Conductor) и кастомный роутинг (на примере Cicreone). Давайте посмотрим, сколько места нам удасться сэкономить если мы их отключим:
для этого мы ищем название пакета, которое использует модуль с support-fragment
Согласно dex-count наши фрагменты занимают 1740 методов.
1740 это не хило. Значит уже не экономим на спичках
Отключаем их простой командой из gradle
implementation('com.android.support:appcompat-v7:27.1.0') { exclude group: 'com.android.support', module: 'support-fragment'}
пытемся собрать и огосподи ! Что же могло пойти не так?
Давайте глянем на логи и разберемся:
Supertypes of the following classes cannot be resolved. Please make sure you have the required dependencies in the classpath:class android.support.v7.app.AppCompatActivity, unresolved supertypes: android.support.v4.app.FragmentActivity
Это попросту значит, что в пакете фрагментов, лежит реализация , которая используется в пакете , которую уже используем мы для своих активностей.
MainActivity -> v7.app.AppCompatActivity -> v4.app.FragmentActivity
В принципе оно и логично, зачем пихать в зависимости то, что нигде не используется. А тут прихожу какой-то я и начинаю все отключать не разобравшись. Ну теперь-то разобрался, надеюсь разобрались и вы.
Помимо этого, была замечена вот какая штука
v13 для библиотеки с якобы минимальной версией v7
Обратившись к документации мы видим очень явную и понятную строчку, прочитав которую не было бы этой статьи, отнявшей у вас время:
Проверяем и убеждаемся
Расследование можно считать закрытым
Спасибо за внимание!
Давайте начнем
Загрузите начальный проект.
В этом туториале вы будете использовать приложение Memo. Memo — это игра, в которой пользователю предлагается сопоставить карты за как можно меньшее время. Кроме того, пользователь может прослушивать разные саундтреки во время игры .
В игре четыре уровня сложности: Beginner (Начальный), Intermediate (Средний), Advanced (Продвинутый ) и Expert (Эксперт). Чем выше уровень сложности, тем больше карт нужно сопоставить. После того, как пользователь выполняет задание на уровень эксперт, он проходит игру. Не хотите попробовать? :]
В настоящее время приложение позволяет пользователю только запускать игру и управлять саундтреками. Запустив игру, вы сможете выйти из нее, просмотреть игровые карточки и засечь время, прошедшее с момента запуска игры.
Откройте проект в Android Studio и ознакомьтесь с файлами. Когда вы закончите, запустите проект на устройстве / эмуляторе, чтобы посмотреть, как он выглядит.
Вы можете поиграть в игру, нажав на кнопку PLAY BEGINNER LEVEL. Сейчас вы уже можете сопоставлять карточки, однако отсутствует таймер, отображающий количество времени, затраченное на решение задачи. Это первое, что мы реализуем в этом туториале.
Однако сначала давайте более подробно рассмотрим, что такое Android Services и как их использовать.
Создание самого уведомления
Пришло время создать само уведомление. Добавьте в NotificationHelper.kt следующее:
Вот что происходит в этом куске кода:
- Если версия Android равна 8 или выше, система создает канал уведомления и возвращает Notification. К сожалению, библиотека поддержки для версий до Android 8 не предоставляет API каналов уведомлений. Подробнее об этой проблеме читайте в официальной документации на тему .
- Возвращается Notification после вызова build() в конструкторе.
Уведомление может обновляться динамически. В этом случае мы будем обновлять текст, если пользователь закроет приложение во время работы службы.
Ниже getNotification() добавьте следующее:
Вот, что здесь происходит:
- Мы обновляем текст в уведомлении, отображаемом в строке состояния, через notificationBuilder.
- Затем говорим диспетчер уведомлений какое уведомление нужно обновить. Для этого мы используем уникальный NOTIFICATION_ID.
Наконец, давайте определим, что происходит, когда пользователь нажимает на уведомление. Добавьте это в начало NotificationHelper.kt:
Здесь вы выполняете ленивую инициализацию PendingIntent, которая запускает MainActivity, когда пользователь нажимает на уведомление.
Прекрасная работа! Уже очень многое было реализовано. Теперь пора запустить Foreground Service.
Описания популярных библиотек
Библиотека CatLoadingView для долгих операций.
Библиотека EventBus — рассылаем и реагируем на события.
joda-time-android — Популярная библиотека Joda-Time для Android, позволяющая работать с датой и временем.
daimajia/AndroidImageSlider — слайдер картинок с анимацией
AndroidSlidingUpPanel — выдвигающая панель сверху или снизу.
Rebound — библиотека для создания анимационных эффектов у компонентов
GSON — библиотека для работы с JSON.
Moshi — современная библиотека для работы с JSON.
OpenCV. Компьютерное зрение Закрытая зона/6-й месяц
svg-android — работа с векторными изображениями SVG
jsoup — парсинг HTML-текстов
opencsv — парсинг CSV-файлов
Android-Query (AQuery) — простой способ использования асинхронных задач и управления UI-элементами
Библиотека Android Asynchronous Http Client — мощная библиотека для асинхронных запросов.
Библиотека OkHttp — HTTP-клиент.
Библиотека Okio для операций ввода/вывода
Библиотека Retrofit для REST.
Библиотеки для загрузки изображений с котиками
Picasso — библиотека для загрузки изображений с разнообразным функционалом.
Glide — похожа по синтаксису и функционалу на Picasso. Библиотека поддерживает анимированные GIF-файлы.
Universal Image Loader — библиотека для загрузки изображений из сети или локальных носителей
koush/ion — и ещё одна популярная библиотека для асинхронных соединений и загрузок изображений.
Fresco | An image management library — Facebook тоже решил внести свою лепту в создании библиотеки для загрузки изображений.
Coil — относительно новая библиотека на Kotlin с корутинами.
Графики и диаграммы
AChartEngine — библиотека для рисования графиков
GraphView — ещё одна библиотека для графиков. Доступны два вида. Встраивается в разметку активности через код.
HoloGraphLibrary — Ещё одна библиотека для рисования графиков.
blackfizz/EazeGraph — и ещё одна библиотека с разными типами графиков.
PhilJay/MPAndroidChart — если не устали, вот вам ещё.
diogobernardino/WilliamChart — до кучи.
Применение методов сервиса.
Присмотритесь и обратите внимание, что Android Studio выдает ошибку из-за того, что не может найти onBind()
Чтобы исправить это добавьте следующее в TimerService:
Давайте разберем этот код немного подробнее:
- Так как мы используем сервис переднего плана, нам не нужно выполнять привязку и мы возвращаем null вместо IBinder. Также заметьте, что мы не используем onCreate(), так как нам не нужна никакая специфическая конфигурация для этого сервиса.
- Здесь мы просматриваем дополнительные возможности Intent, чтобы получить значение, которое содержит ключ SERVICE_COMMAND. Это значение указывает на то, какое действие должен выполнить сервис.
- Если система завершает работу сервиса из-за нехватки памяти, START_NOT_STICKY говорит системе о том, что не стоит создавать службу с неопределенным Intent. Альтернативные константы: START_STICKY и START_REDELIVER_INTENT. Если вас интересует функционал этих констант, ознакомьтесь с официальной документацией по .
- Временно удалите все колбэки Handler, чтобы не засорять память. Кроме того, стоит очистить ресурсы, отменив все Job таймера, поскольку на следующем шаге сервис будет уже уничтожен.