Telegram Web
​​Темная тема с Material Design Components
#mdc #theme

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

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

1️⃣ Не использовать абсолютно чёрный цвет. По умолчанию в тёмной теме фоновый цвет — это не #000000, а #121212. Полностью чёрный цвет поможет увеличить время работы устройства на OLED-дисплеях, однако в приложении могут быть иконки, анимации, контрастные изображения, которые будут выглядеть хуже на полностью чёрном цвете. Ну и главная причина — это увеличение нагрузки на глаза. Поэтому, лучше использовать «не до конца чёрный цвет» 😁

2️⃣ Оттенки главных цветов. В палитре Material Design цвета нумеруются по тонам от 50 (наиболее светлый тон) до 900 (наиболее тёмный тон). Интересно, что для светлой темы стоит выбирать colorPrimary в тоне около 500, а для тёмной — около 200. Если вы используете colorPrimaryVariant, то в тёмной теме можно взять colorPrimary из светлой темы.

3️⃣ Обратить внимание на цвета поверхностей и тени. Яркие цвета могут иметь положительное влияние на приложение, если включена светлая тема. Однако, если используется темная тема, это должно интерпретироваться как желание пользователя использовать приглушенную, менее яркую цветовую схему. Стоит также обратить внимание на те тени, которые отображатся на поверхностях.

Больше рекомендаций по настройке тёмной темы можно найти тут.
​​Как участвовать в развитии Kotlin?
#kotlin

Сегодня первый день конференции KotlinConf 2020, и один из докладов был посвящён тому, как любой разработчик может поучаствовать в развитии Kotlin.

🔸участвовать в Early Access Preview. Для каждого релиза, команда Kotlin делает несколько alpha-версий, где каждый может попробовать самые последние фичи до того, как они пойдут в production. Это крутая возможность, если вы любите попробовать новинки первым. Подробнее тут.

🔸вносить вклад в компилятор, стандартные библиотеки и tooling. Для этого нужно прочитать инструкцию о том, как правильно делать contribute в Kotlin, посмотреть открытие задачи и начать писать код.

🔸создавайте новые библиотеки или участвуйте в развитии других. Помимо стандартной библиотеки, Kotlin имеет ряд дополнительных (kotlinx) библиотек, расширяющих его функциональность. Каждая библиотека kotlinx разрабатывается в отдельном репозитории, имеет собственный цикл версий и выпуска. Например, вы можете участвовать в развитии coroutines, serialization или ktor.

🔸улучшайте документацию. Если вы нашли ошибку в документации Kotlin, вы можете сделать pull request с правкой в официальном репозитории для документации.

🔸создавайте tutorials и видео. Если вам интересно делать статьи или обучающие материалы, вы можете поделиться ими, написав в [email protected]

Чуть больше информации можно взять тут.
​​Отправка данных между Fragments
#fragment

Для передачи данных между двумя фрагментами, существовало одно распространённое API — targetFragment.

По сути, targetFragment предоставляет нам способ получения данных через back stack, а всё что нам нужно — это переопределить onActivityResult в вызывающем фрагменте.

Несмотря на кажующуюся простоту, это API — не очень удобное.
Во-первых, targetFragment будет работать если фрагменты находятся в одном и том же менеджере.
Во-вторых, API разбросано по коду и становится непонятно, откуда прилетел тот или иной кусок данных.

Не так давно появилось новое решение — FragmentResultOwner. По сути, это callback, который есть у каждого FragmentManager.
Это изменение позволяет отдельным фрагментам взаимодействовать друг с другом, отправляя результаты фрагмента и прослушивая эти результаты, не требуя, чтобы фрагменты имели прямые ссылки друг на друга.

Работает он примерно так:
setFragmentResultListener("requestKey") { key, bundle ->
val result = bundle.getString("name")
// Do something with the result...
}


А в том месте, где мы хотим отправить информацию нужно вызвать:
tvSave.setOnClickListener {
setResult("requestKey", bundleOf("name" to updatedValue))
}


Точно такого же слушателя мы можем добавить и для childfragmentmanager. В целом, новое API выглядит гораздо интереснее предыдущего и виден явный прогресс.
​​TextAppearance или Style
#design #view

Android даёт нам несколько способов установить атрибуты стиля для TextView. Есть два самых часто используемых:
1) Применение нужных атрибутов напрямую в вёрстке:

<TextView
android:textSize="16sp"
android:textColor="#fff"

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

2) Использование Style для TextView, например:

<TextView
style="@style/Widget.MyApp.TextView"

Здесь мы уже можем переиспользовать настройки, заданные в стиле. И вроде этот подход выглядит идеальным и правильным, однако существует ещё и третий способ кастомизации TextView — это textAppearance.

<TextView
android:textAppearance="?textAppearanceBody1"


На самом деле, это довольно интересное свойство. Оно позволяет нам установить ограниченный набор атрибутов, специфичных только для текста: цвет текста, его размер, шрифт, семейство цветов и т.д. При этом, в Android Material сущестуют 13 стандартных textAppearance, которые мы можем дополнить и использовать у себя в проектах. Подробнее можно посмотреть тут.

Порядок установки атрибутов такой: сначала применяются атрибуты textAppearance, дальше атрибуты стиля, и потом те, что вы напрямую определили для View.

Подробнее можно прочитать тут.
Любопытный комментаррий по поводу последнего поста от @terrakok.

Существует свойства android:lineSpacingMultiplier, добавляющее дополнительный интервал между строками через коэффициент и которое, по логике, подходит для TextView и должно быть в поддерживаемом списоке textAppearance.

Но в списке свойств его нет. Поэтому, будьте внимательны, если решили заморочиться pixel-perfect дизайном у себя. Единственным выходом будет тут применение style вместо textAppearance.
Круто, когда подписчики делятся в личке своим опытом и совсем не очевидными вещами по разработке. @maks_frei дал ещё одно уточнение по поводу TextView и textAppearance.

lineSpacingMultiplier, как и lineSpacingExtra который работает в паре с первым, можно добавить только в стиль, но не в textAppearance. Это создаёт некоторые неудобства, когда страдаешь пиксель перфекционизмом.

Но, в противовес, можно использовать MaterialTextView, который умеет читать тэг lineHeight с textApperance. Этот тэг указывает, какое точно должно быть межстрочное расстояние, что является более удобным вариантом предыдущих двух тэгов. Единственный нюанс — MaterialTextView требует Material темы.
Ну а если у вас в приложении стоит полностью Material (не Bridge) тема, то и обычный TextView автоматически инфлейтится в MaterialTextView.

Чуть больше про MaterialTextView можно почитать тут.
​​​​Don't kill my app!

Для нас не является секретом тот факт, что в мире существуют десятки разных производителей устройств под Android. Многие их них дописывают Android под себя, пытаясь заботиться о пользователе.

Однако, порой подобные оптимизации заходят слишком далеко, и приложения перестают корректно работать: не приходят уведомления, неправильно работает камера и т.д.

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

Любопытно, что OnePlus вырвался на первое место, Huawei, Samsung и Xiaomi сразу на ним, а большинство no-name производителей находятся в самом низу рейтинга.
​​StateFlow
#kotlin #flow

Уже многие используют в своих проектах Flow вместо RxJava, но всё ещё остаётся LiveData. В качестве альтернативы, есть StateFlow, который приходит на замену ConflatedBroadcastChannel.

По принципам работы, StateFlow очень похож на LiveData. Чтобы помочь вам в его использовании, нашёл несколько статей.

В этой автор решил использовать StateFlow для класса SingleLiveEvent, который бывает полезен при публикации каких-то действий нашим слушателям. Также описана разница между методами launch и launchWhenStarted.

Тут описан неплохой пример того, как использовать StateFlow вместо LiveData.

В этой статье, тем более она на русском, описано то, как устроен StateFlow под капотом, его преимущества над другими решениями.
​​EvadeMe
#library #security

Для того, чтобы избежать анализа вашего приложения со стороны, существует достаточно много способов.
Сегодня мне попалась интересная статья, где описывается ряд методов, при помощи которых можно проверить:

🔸подключен ли телефон к компьютеру по USB или Wifi;
🔸установлены ли на устройстве приложения для проверки трафика;
🔸выполняется ли подключение через VPN;
🔸является ли устройство эмулятором;
🔸есть ли root-доступ.

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

Автор собрал весь набор методов и сделал небольшую библиотеку под названием EvadeMe. Возможно, какие-то из них будут вам полезны, почитать подробнее можно тут.
​​Бесконечный список с Paging Library и Flow
#flow #jetpack

Сегодня вышел релиз coroutines 1.4.0, где было много классных изменений, связанных с Flow.
Мне кажется, что сегодня Flow довольно стабилен, и нет смысла не использовать его в production-проектах, тем более, когда стабильными стали StateFlow и SharedFlow.

Хочу поделиться статьёй, где автор рассказывает о создании бесконечного списка с помощью объединения Flow и Paging Library.

В итоге получился довольно лаконичный код, где разработчику нужно по минимуму заморачиваться с логикой получения списка.
​​Жизнь в Германии
#интервью #экспаты

Итак, второе интервью на канале про жизнь в разных странах!

Наш гость — Василий Лютиков. Он проживает в городе Остфильдерн, недалеко от Штутгарта в Германии. Он работает iOS-разработчиком в компании Mädchenflohmarkt GmbH, компания, которая позволяет избавится от лишних вещей в женском гардеробе и название которой довольно сложно произнести русскоговорящему человеку.

Хотя Василий и не Android-разработчик, уверен, что сможет дать кучу информации про Германию всем нам.

У каждого, как всегда, есть возможность задать свои вопросы в форме тут.
​​Уроки по Navigation Component
#navigation #jetpack #poll

Разработчики от Google начали делать раздел, посвящённый современным паттернам Android-разработки, где детально описывают, как применять современные подходы разработки для приложений.

Недавно у них завершилась неделя по Navigation Architecture Component, где нам дали краткое, но ёмкое overview по этому компоненту.

🔸в первом эпизоде описываются базовые принципы работы navigation: как добавить её в приложение, из каких частей она состоит, как работают некоторые части API, чтобы заставить навигацию работать. В текстовом виде можно почитать тут.

🔸во втором видео говорится об использовании navgiation для показа диалогов. Это пример того, как использовать navigation вне NavHostFragment. В текстовом виде тут.

🔸в третьем эпизоде говорится о SafeArgs: это способ безопасной передачи данных между компонентами в navgiaton. В тексте тут.

🔸в четвёртом эпизоде информация о механизме Deep Links, и о том как реализовать их при помощи navigation. В тексте тут.

🔸последний эпизод — это Q&A сессия со спикерами, где они отвечают на популярные вопросы: multiple backstacks, поддержка Jetpack Compose, Up-vs-Back, saving state и другое. Текста, к сожалению, нет, но и сделать его из такого большого видео было бы проблематично.

Также приложение, которое использовалось в качестве примера на протяжении всей серии.

А вы используете, Navigation Component в своих проектах?
​​Автоматическое обновление зависимостей gradle
#gradle #library

Обновление зависимостей gradle, особенно в большом проекте, может стать отдельной задачей. 🤦‍♂️
Разработчикам чаще всего приходится вручную проверять новые версии, что приводит к потере времени. Нет смысла не делать обновления: разработчики делают правки в библиотеках, улучшают их производительность и качество.

Есть любопытное решение, которое я не встречал раньше — Releases Hub Gradle Plugin. Плагин проверяет текущие версии библиотек (например во время сборки билда на CI) и делает PR с обновлениями. Каждый PR содержит информацию об новых фичах, добавленных в обновлении, ссылки на документацию, настройки веток и т.д.

Выглядит довольно интересно, но всё равно на разработчике и QA лежит задача проверки работоспособности приложения после каждого обновления, особенно когда дело касается важных библиотек.

Больше почитать о плагине можно тут.
​​Jetpack Compose for Desktop
#jetpack #compose

Сегодня появилась хорошая новость: команда JetBrains анонсировала выход первого релиза Jetpack Compose for Desktop — фреимворк для UI, который теперь позволяет делать UI для компьютеров!

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

Уже есть несколько примеров приложений, а чуть больше деталей об инструменте можно почитать тут.
​​Mobius 2020
#conference

Уже на следующей неделе, с 11 по 14 ноября, нас ожидает конференция для мобильных разработчиков — Mobius 2020.
Расписание полностью сформировано, и для нашего удобства доклады разделены на 4 дня.

Поделюсь парочкой интересны для меня докладов:

В докладе Увлекательная жизнь в панели уведомлений, Кирилл Розов расскажет про работу с уведомлениями, их настройкой в разных версиях Android. Выглядит интересно, и мне кажется, что notification часто недооценивают разработчики и не используют их на 100%.

Есть сразу несколько докладов, связанных с декларативными фреимворками, вот один их них: Декларативный UI сегодня — Петр Козлов и другие спикеры сравнят существующие решения для декларативного UI, в каком статусе они находятся сегодня и стоит ли использовать их в production.

В докладе Offline-mode в несколько строк кода Алексей Быков поделится тем, как правильно создавать абстракцию для работы с данными и реализовать кэширование в несколько строк кода. Посмотрим, насколько подобный подход универсален для всех приложений.

Есть несколько воркшопов, и вот один из них: Flutter Zero LiveShow от Александра Денисова, где в прямом эфире будет написано приложение с нуля на Flutter. Лично мне интересно посмотреть итоговый результат. 🤓

Всё расписание можно почитать тут, а купить билеты со скидкой по промокоду AndroidLive2020aupc на конференцию можно тут.

Но это ещё не всё. Не могу оставить вас без шанса выиграть один билет на конференцию бесплатно. 🤗
Всё что нужно сделать — это оставить свой никнейм в Telegram в этой форме, результаты розыгрыша будут объявлены 9 ноября в 18:00.
​​Результаты розыгрыша билета на Mobius 2020
#конкурс #conference

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

В конкурсе принял участие 41 человек. При помощи генератора случайных чисел был выбран победитель — @ddgradd, с чем я его поздравляю! 🎊

Видео с выбором победителя тут. Обязательно участвуйте в новых конкурсах и конечно же выигрывайте!
​​История про memory leaks, WeakReferences и ошибки при исправлении
#article

Попалась любопытная статья, где рассказывается о неверном использовании механизма ссылок WeakReference.
В ней описывается пример использования WeakReference как костыля для работы с утечками памяти. Автор решил изучить вопрос, и рассмотрел несколько вариантов борьбы с этой проблемой.

Описываются все плюсы и минусы решений. Тут и EventBus, и LiveData, и RxJava с BehaviorRelay, да и многие другие, менее очевидные решения.

Множество информации можно почерпнуть тут.
​​Несколько советов по Kotlin для Android разработчиков
#article #kotlin

Ни для кого не секрет, что сегодня Kotlin — это официальный язык для нативной разработки под Android. Он призван уменьшить количество написанного кода и улучшить его качество.
В целом, со своей задачей он справляется, однако не все разработчики используют все фичи этого языка при написании кода, делая всё «по старинке».

Попалась статья, которая даёт 7 советов написания кода «Kotlinic» способом. Вот несколько из них:

🔸используйте функцию `let`, чтобы проверить поле на null. Проверка на null — это очень распространённое действие, несмотря на то, что в Kotlin есть nullable-переменные. Многие забывают, что существует хорошая альтернатива if not null выражению — функция let, в которой код превращается в a?.let { foo(a) }.

🔸используйте функции для создания списков. Очень часто мы для заполнения списков используем цикл for и забываем про средста Kotlin.
Например, заполнить список значениями по умолчанию можно в одну строку:
val list = IntArray(10) { 1 }.asList().
Но подобным образом можно заполнить список разными значениями:
val list = List(5, {it*2}), что даст нам список от 0 до 8 с шагом 2.

🔸используйте `require` и `check` для работы с исключениями. Например, если мы хотим, чтобы наша переменная была больше нуля, то можно вызвать функцию:
require(n >0) { Should be more than zero }.

🔸используйте `apply` и `with`, чтобы уменьшить повторы кода. Эти две функции полезны, если мы хотим сделать несколько действий с нашей переменной. Такое часто бывает при работе сo RecyclerView, которому нужно задать layout manager и несколько других свойств.

🔸используйте методы `partition` и `groupBy` для списков. Эти функции помогают нам сделать несколько списков из одного по заданному условию.
Добавлю сюда ещё функцию groupByTo, в которой мы можем указать то, в какую структуру превратить наш список.

🔸используйте method references вместо lambda expressions для простых действий. Довольно интересный совет, который не так часто видишь в коде.
Например, у нас есть список объектов Person, который мы хотим преобразовать в список имён. Мы можем использовать method references в map, чтобы сделать это более красивым способом:
val names = persons.map(Person::name).

Надеюсь, что вы нашли для себя полезный совет, который будете применять на практике. 🤓
​​Немного про let
#kotlin #article

Во вчерашнем посте был первый совет с использованием let для проверки переменной на null. @atlantik_hak подкинул годную статью, где описываются примеры, когда не стоит использовать let для этих целей, а когда let — самое лучшее решение для проверки.

Итак, когда лучше не использовать let:

для проверки на null immutable переменной. Хотя и запись a?.let { foo(a) } получается довольно изящной, она генерирует лишнюю переменную в байткоде, в отличии от аналога if not null. Врядли вы заметите огромную разницу, но если можно избежать создания лишней переменной, то почему бы этого не сделать.

если вы хотите использовать переменную только внутри let. Чаще всего мы делаем проверку именно для того, чтобы использовать её внутри блока. Например, мы хотим что-то сделать с webView:
webviewSetting?.let {
it.javaScriptEnabled = true
it.databaseEnabled = true
}


вместо этого можно использовать функцию run
webviewSetting?.run {
javaScriptEnabled = true
databaseEnabled = true
}

который уберёт лишние it.

если хотите передать переменную дальше по цепочке. Например, если вы хотите указать размер списка, если он не null, а дальше что-то продолжить делать с ним. Альтернативным решением будет использование also, хотя это тоже не идеальное решение.

Когда же тогда использовать let?
🟢 для проверки на null mutable переменной. Тут хорошо подходит let, так как он избавляет нас от дополнительного ? при взаимодействии с переменной.
private var str: String? = null

fun process() {
str?.let { /*Do something*/ }
}


🟢 если хотите использовать переменную снаружи от let. Например, если вы хотите проициализировать другие переменные тем классом, что был у вас:
var javaScriptEnabled = false
var databaseEnabled = false

webviewSetting?.let {
javaScriptEnabled = it.javaScriptEnabled
databaseEnabled = it.databaseEnabled
}


Это удобнее для review кода, чем функция run.

🟢 когда у вас есть проверка из цепочки `?`. Например:
return string?.asIterable()?.distinct()?.sorted()
генерирует больше байткода, чем:
return string?.let {
it.asIterable().distinct().sorted()
}


Спасибо подписчикам, которые дают обратную связь по постам ✌️.
И уверен, что теперь вы будете использовать let аккуратнее.
​​Как сделать компилятор Kotlin умнее
#article #kotlin

Компилятор Kotlin довольно умный и даёт нам подсказки о наших же ошибках.
Одной из самых заметных фич в компиляторе Kotlin является smart casting. Это значит, что компилятор может выполнять приведение типов на основе проверок, выполненных разработчиком.

Однако механизм smart casting не безграничен. Например, компилятор может проверить переменные только в том блоке, где эти проверки были непосредственно выполнены.

Немногие разработчики знают, что можно написать контракты, которые помогут компилятору в его работе. Например, если вы создадите контракт, функция которого возвращает true, в случае если переменная не равна null, компилятор выполнит приведение типа и сделает нашу переменную non-nullable.

Contract DSL выглядит так:
fun foo(): Boolean {
contract {
// Effect
}
// Function body
}


Можно использовать следующие функции для того, чтобы описать контракт:
🔸returns(value) — описывает ситуацию, когда функция нормально возвращается с указанным значением.
🔸returnsNotNull() — описывает ситуацию, когда функция возвращает non-nullable значение.
🔸implies(booleanExpression) — указывает, что данный наблюдаемый эффект будет истинным при заданном booleanExpression
🔸callsInPlace(lambda, kind) — позволяет указать, как часто будет выполняться данная лямбда.

Краткое описание параметров способно запутать, но можно обратиться к статье, чтобы получить больше информации с примерами. Надеюсь, что в будущем появится ещё больше функций для описания контрактов 🤟.
2025/08/30 12:13:54
Back to Top
HTML Embed Code: