Telegram Web
​​Как оптимизировать RecyclerView?
#комментарии #recyclerview

Ни для кого не секрет, что сегодня RecyclerView — это базовый элемент для показа списков в приложениях. И очень важно, чтобы он работал максимально плавно.

Автор статьи предлагает следующие оптимизации:

🔸использование библиотек для загрузки изображений. Garbage collector мог бы быть причиной неотвечающего UI, если бы не bitmap pool, который встроен в большинство современных библиотек для загрузки изображений. Думаю, что мало кто сегодня пытается самостоятельно управлять показом изображений вручную, поэтому продолжайте делегировать все задачи, связанные с загрузкой изображений специальным библиотекам.

🔸установите ширину и высоту для ImageView. Очень часто изображения, получаемые с сервера имеют динамические параметры ширины и высоты. Если мы показываем изображения без учёта этих параметров, то при полной загрузке можем получить «мигание» интерфейса. Чтобы этого избежать, попробуйте вычислить ширину и высоту или соотношение сторон заранее, до загрузки картинки.

🔸оптимизируйте метод onBindViewHolder. Проверьте метод onBindViewHolder и сделайте его максимально легким. Это также даст прирост к производительности RecyclerView

🔸используйте DiffUtil. При обновлении адаптера старайтесь использовать DiffUtil. Под капотом он использует методы для изменения элементов по позициям, а не полное обновление списка (notifyDataSetChanged). Кстати, если хотите ещё больше оптимизировать свой список, попробуйте использовать асинхронный DiffUtil на coroutines. Ссылка с деталями тут.

🔸избегайте вложенных view. Довольно базовое правило, нарушение которого становится ещё более критичным в RecyclerView. Добавлю, что тут важно следить за layout, которые использут веса для отрисовки.

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

🔸переиспользуйте RecyclerViewPool. Довольно хорошей оптимизацией является переиспользование RecyclerViewPool при наличии одинаковых элементов. Пример можно посмотреть в статье.

🔸поэкспериментируйте с setItemViewCacheSize. Из документации следует, что этот параметр устанавливает количество ViewHolder, которые не показаны на экране перед добавлением их в RecyclerViewPool. Мы можем поэкспериментировать с этим параметром, чтобы увеличить количество ViewHolder, невидимых на экране и уменьшить количество вызовов onBindViewHolder.

А что вы бы ещё добавили к этому списку?
​​Podlodka Android Crew — 2 сезон
#конференции

Летом ребята из Podlodka делали двухнедельную онлайн конференцию для Android-разработчиков. И вот, уже через неделю начинается второй сезон Podlodka Android Crew!

Что нас ждёт:
🌟 парное программирование от Дениса Неклюдова и Степана Гончарова;
💰доклад о том, как из мобильного разработчика вырасти в СТО;
🔥собеседование наоборот: теперь будут собеседовать не людей с конференции, а экспертов, которые там присутствуют;
☕️куча сессий и, конечно же, холиваров.

Начало конференции — 5 октября. До четверга, цена билета — 3400 рублей, что весьма демократично, учитывая количество контента. Подробнее о программе и билетах тут.

И снова, у вас, подписчиков Android Live, есть шанс выиграть билет бесплатно. Для этого не нужно никуда подписываться: просто оставь свой ник в форме до 1 октября 18:00. В этот же день будет розыгрыш одного билета.

До встречи на конференции!
​​Room и связь Many to Many
#room

На мой взгляд, одна из самых неудобных вещей, которая есть в Room — это работа со связью Many to Many.

Для тех, кто не использовал эту связь в Room, я расскажу вкратце. Больше деталей можно почитать тут.
Для её создания в Room есть следующий механизм:
🔸создаётся ассоциативная таблица с идентификаторами первой и второй таблицы;
🔸создаётся новый data-класс, где прописывается связь через Junction, указывая эту таблицу в качестве связи.

По идее, все довольно просто, но главная сложность возникает в фильтрации данных. В документации показан пример с получением полного списка данных, но если её нужно сделать, то единственный вариант — использование @RawQuery вместо @Query и генерирования запроса вручную.
Для такой связи нужно будет создать INNER JOIN по ассоциативной таблице, и дальше применить нужные фильтры.

Главный недостаток тут — отсутствие проверки правильности запроса во время компиляции, поэтому будьте особенно внимательны при его составлении.
​​Результаты конкурса Podlodka Android Crew — 2 сезон
#конкурс

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

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

Видео с выбором победителя тут. Обязательно участвуйте в новых конкурсах!
Поиск работы, оптимизация резюме. Взгляд со стороны HR
#конференции

Каждый из разработчиков рано или поздно задумывается о смене работы. Мы готовимся к собеседованиям, учим алгоритмы, но забываем о том, что прежде всего видят рекрутеры — резюме. У многих даже нет хорошо оформленного CV! 😩

В сообществе GDG Bryansk в это воскресенье, 4 октября будет митап, посвящённый поиску работы и оптимизации резюме со стороны HR.

Поликарпов Дмитрий, наш спикер, занимается подбором людей в IT с 2013 года и расскажет нам о поиске работы и ошибках в резюме соискателей.

Запись митапа будет. Тех, кто будет на мероприятии онлайн, ждет сюрприз 🎊, о котором вы узнаете в начале митапа.

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

До встречи на митапе!😎
​​Оптимизируем скорость сборки приложения
#gradle

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

Но есть советы, которые можно попробовать применить сразу после старта проекта.
Для начала выполните следуюущую команду, чтобы понять текущую скорость сборки:
./gradlew --profile --offline --rerun-tasks assembleDebug

Начнём улучшать:
🔹применим org.gradle.configureondemand=true — флаг включает конфигурацию проектов по запросу, что позволяет собирать только то, что участвует в сборке.

🔹увеличим Java heap при помощи org.gradle.jvmargs=-Xmx1536m, если позволяет ваша оперативная память.

🔹задействуем kapt.use.worker.api=true. Флаг задействует worker API для стадии annotation processing в kapt, а также перемещает выполнение этой стадии отдельно от Kotlin Compile Daemon.

🔹включим параллельную сборку мультимодульных проектов при помощи org.gradle.parallel=true.

🔹если в проекте есть room, то добавим room.incremental = true. Начиная с версии 2.3.0, флаг включен по умолчанию.

🔹добавим org.gradle.unsafe.watch-fs=true. Работает флаг так: чтобы gradle мог определить, надо выполнять задачу или нет, ему необходимо проверить, был ли изменён файл с момента последней сборки. Daemon хранит эту информацию в памяти, если задействован данный флаг. Иначе — он собирает её для каждой сборки. Больше деталей можно узнать тут.

🔹можно включить конфигурационный кэш при помощи org.gradle.unsafe.configuration-cache=true.

🔹если у вас есть png в проекте, то можно выключить автоматическое сжатие png-файлов для сборок, отличных от debug, где оно автоматически выключено при помощи crunchPngs false.

🔹посмотрите, чтобы у вас везде в проекте были указаны точные названия версий, избегайте названий в виде 1.+.

Конечно, это далеко не полный список возможных улучшений, но даже эти флаги ускорят сборку вашего проекта. Чуть больше информации о них можно почитать в статье.
​​Безопасность современных Android-смартфонов
#security

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

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

🔸три статьи про шифрование: первая, вторая и третья части. Они расскажут о том, как шифровать данные внутри приложения и об их хранении.

🔸немного о том, как работает биометрия, и как её лучше использовать.

🔸чуть позже нас ждёт ещё четыре статьи: про нативный код, сертификаты и изменения безопасности в Android 11.
​​Наименование строковых ресурсов
#resources

Мы, как разработчики, часто следуем различным практикам, которые улучшают код. Например, мы следуем camelCase при написании переменных.

Но часто мы не обращаем внимание на то, как пишем ресурсы в приложении. Давайте поговорим о том, как лучше именовать ресурсы в файле strings.xml.

В целом, существует так называемая практика <HOW>_<DESCRIPTION>. Это практика, где первым словом вы указываете то, как использовать ресурс в проекте, а вторым — что означает данный ресурс. Например, label_home или hint_user_name.

В своих проектах я немного расширил эту технику до <HOW>_<WHERE>_<DESCRIPTION>. В этом случае where — это экран или модуль, где используется ресурс. Например, title_registration_pass. Если ресурс используется в нескольких местах, то параметр where опускается.

Для себя также обозначил следующие how:
🔸title — заголовки;
🔸hint — подсказки в edittext;
🔸msg — сообщения или обычные текста на экранах;
🔸error — сообщения об ошибках;
🔸action — кнопки или какие-то действия.

Подобный порядок делает использование ресурсов удобным, что особенно актуально, если ваш проект переведён на нескольких языков.
​​Разбираемся в Jetpack Compose
#jetpack #compose

Сегодня Jetpack Compose — это технология, которая у каждого на слуху. Думаю, что после появления финальной версии, многие приложения будут создаваться с ней, а знание Compose будет обязательным, как сегодня знания Kotlin.

В статье делается краткий обзор Compose, его сравнение с layout и почему он принесёт пользу в современный мир разработки.

На мой взгляд, это хорошая статья, если вы совсем не знакомы с понятием декларативного UI или задавали себе вопрос, для чего конкретно в будущем использовать Compose.
​​Темная тема с 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-разработчик, уверен, что сможет дать кучу информации про Германию всем нам.

У каждого, как всегда, есть возможность задать свои вопросы в форме тут.
2025/09/05 16:58:21
Back to Top
HTML Embed Code: