Telegram Web
​​​​Flutter vs Kotlin Multiplatform Mobile
#youtube

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

Трансляция пройдёт онлайн, 24 марта в 18:00 по МСК, как всегда на Youtube-канале AndroidLive. Ссылка на трансляцию тут, задавайте свои вопросы и темы для сравнения тут.

До встречи!🤟
​​Новое API для Flow и UI-слоя
#flow #jetpack

Пару дней назад Google выпустили обновление для API Flow, где заметно улучшили его взаимодействие с UI-слоем.

Если говорить о текущем состоянии, то, в целом, мы уже можем использовать Flow и отказаться от LiveData. Правда, есть одно замечание: может быть не безопасно подписываться в UI-слое на холодный Flow, если мы вручную не можем отменить задачу, которая им выполняется. В качестве примера в статье приводится обновление локации пользователя и возможное текущее решение.

Теперь у нас есть три новых метода:
🔸 LifecycleOwner.addRepeatingJob — принимает Lifecycle.State в качестве параметра и используется для автоматического создания и старта новой корутины и отменяет её, когда состояние достигнет противоположного значения.

🔸Lifecycle.repeatOnLifecycle — аналогичная функция, но только для Lifecycle.

🔸Flow.flowWithLifecycle — этот API использует предыдущую функцию под капотом и также закрывает «продьюсера» в момент противоположного состояния жизненного цикла. Кроме этого, данную фукнцию можно встроить напрямую в целочку вызова Flow, что делает вызов более лаконичным. Важно помнить, что эта функция работает по аналогии с Flow.flowOn, которая затрагивает только цепочку, которая выше неё и добавляет буфер для предотвращения backpressure.

В целом, в статье упоминается то, что теперь можно полностью эмитировать поведение LiveData и использовать Flow в приложениях, где вы хотите использовать только Kotlin API. Это здорово, но пока API находится в alpha-версии и стоит тащить его к себе аккуратно.

Кроме этого, если вам это нужно, добавили поддержку data binding для Flow. Детали тут.
​​Countdown Timer с Jetpack Compose
#jetpack #compose

Многие знают о том, что сразу после выхода beta-версии Jetpack Compose Google анонсировали Android Dev Challenge. Это возможность попробовать новую технологию, поучаствовать в конкурсе и выиграть призы.

Для тех, кто не мог участвовать (а разработчики из России не могли 😑) есть возможность посмотреть на хороший пример приложения со второй недели этого конкурса.

В задачу входило написание таймера, где UI должен полностью быть на Compose. Можно ознакомиться с такими понятиями, как State, Composition, Initial composition, rememberSaveable и т.д. Ну и да, много когда на Compose, что не может не радовать.

Ссылка на статью тут, а код можно найти тут
​​Emoji под капотом
#view

Любопытная статья о том, как работают emoji под капотом.

По сути emoji — это стандартные Unicode-символы, которые ведут себя так же, как и обычные буквы: вы можете их вводить с клавиатуры, копировать, выделять и т.д.

Интересно, что это также bitmap font, где каждый символ — это или растровое или векторное изображение. Все зависит от операционной системы – на Android это битмапы размером 128×128. Вот главная причина, почему emoji выглядят по-разному на различных устройствах. Ну и некоторые приложения или вендоры переопределяют шрифты, чтобы отрисовать их по-своему.

В статье автор также рассматривает ситуации:
🔸когда emoji пересекаются с уже существующими пиктограммами;
🔸почему все emoji выглядят одинаково при любом выбранном шрифте;
🔸какие проблемы могут быть при нахождении длины строки и emoji;
🔸как работает модификация тона кожи;
🔸как можно комбинировать несколько emoji в одну и многое другое.

Ссылка на статью тут. Лично мне было интересно узнать столько новых деталей про такой распространённый инструмент. 🙃
​​Исследование поведения подключённых библиотек
#gradle #security

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

Есть пара советов, которые помогут исследовать сторонние библиотеки:

0️⃣ Merged manifest view. Функциональность позволяет сделать общий AndroidManifest из всех подключённых в проект библиотек. Таким образом вы сможете посмотреть, какие дополнительные сервисы, разрешения, Activity и т.д. вносят ваши зависимости.
Для этого нужно кликнуть Merged Manifest внизу открытого AndroidManifest-файла. Обязательно посмотрите, нет ли каких-то скрытых запросов разрешений, и если нет возможности отказаться от библиотеки, то выключите их при помощи этого кода:
<uses-permission android:name="SOME_PERMISSION"
tools:node="remove"/>


1️⃣ Просмотр зависимостей модуля. Эта штука поможет вам настроить транзитивные зависимости, а также проанализировать то, какие дополнительные штуки включает добавленная библиотека. Подробнее почитать можно тут.

2️⃣ Аудит доступа к данным. Достаточно новая фича, которая позволяет посмотреть использование приватных данных вашим приложением. Делается это при помощи AppOpsManager.OnOpNotedCallback, куда приходят методы с пометкой приватного доступа, например «share with friends».
Я сам на практике не использовал, но выглядит интересно. Кроме того, можно зарегистрировать свой атрибут для приватной операции, который также будет попадать в этот callback. Детали тут.

А какие ещё методы исследования библиотек вы знаете?
​​Про PendingIntent
#interview

PendingIntent — довольно важная часть приложений под Android, о которой мы часто забываем и не до конца понимаем, для чего она нужна. Так как с Android 12 у нас добавились изменения, связанные с работой с PendingIntent, давайте посмотрим, что это за класс, ну и поговорим про изменения.

PendingIntent по сути — обёртка над обычным Intent, которая позволяет другому приложению выполнить какое-то действие в будущем от имени вашего приложения.

Отсюда мы сразу выносим две ключевые разницы:
🔹событие связано с будущим действием;
🔹это действие происходит от имени вашего приложения.

Область применения PendingIntent довольно обширна. Самые распространённые кейсы — это работа с AlarmManager и уведомлениями. Тут можно найти ещё пару кейсов, например при взаимодействии с получением результата от другого приложения.

PendingIntent создаётся с флагами, которые влияют на его работу.

🔸FLAG_IMMUTABLE — означает, что Intent внутри PendingIntent не может быть модифицирован другим приложением. Важно помнить, что приложение всегда может менять свои PendingIntent, даже если они неизменяемы для других приложений. До Android 12 все PendingIntent, созданные без этого флага были изменяемыми по умолчанию.

🔸FLAG_MUTABLE — означает, что компонент внутри PendingIntent может быть модифицирован другим приложением при помощи PendingIntent.send(). Флаг был добавлен в Android 12, и очень важно заполнять ComponentName при такой модификации.

🔸FLAG_UPDATE_CURRENT — означает, что необходимо обновить содержимое компонента без создания нового PendingIntent. Если такого нет, то будет создан новый.

🔸FLAG_ONE_SHOT — позволяет PendingIntent выполнять действие только один раз.

🔸FLAG_CANCEL_CURRENT — закрывает существующий PendingIntent, что особенно важно, если вы хотите поменять приложение, на которое завязан ваш текущий PendingIntent.

Почитать детальнее о том, как использовать этот компонент в Android 12 можно тут.
​​Старт в KMM
#kotlin #kmm #beginners

Коллеги из чата про KMM делают доку для погружения и ознакомления с этой технологией. Будет полезно всем, и тем кто ещё только собирается изучать технологию, и тем, кто уже в теме.

На ресурсе можно найти информацию:
🔹о том, почему и когда стоит выбирать KMM для проекта;
🔹как настроить окружение для разработки (особенно актуально для iOS-разработчиков);
🔹как написать первый проект;
🔹как работать с некоторыми из библиотек и многое другое.

Важно, что проект opensource и каждый может внести свой вклад в эту доку. Ссылка на сайт тут.
​​Паттерны проектирования в Android разработке
#design #patterns #beginners

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

Если вы хотите связать существующие паттерны с Android-разработкой, то есть отличная статья, которая разбирает основные паттерны и описывает примеры, которые есть в Android. Вот некоторые из шаблонов: Builder, DI, Singleton, Factory, Adapter, Facade, Observer и многие другие.

Ну и обильные примеры кода также весьма радуют. Ссылка на статью тут.
​​Google IO 2021
#conference

На этой неделе Google анонсировал даты конференции для Android-разработчиков — Google IO 2021. В этом году она пройдёт с 18—20 мая только онлайн, без возможности оффлайн участия.

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

Уверен, что будет детально рассказано про Jetpack Compose и его статус, возможно он уже будет production ready.

Тут можно решить небольшой ребус, а тут зарегистрироваться на само мероприятие, оно полностью бесплатное.

Ну и вы узнаете обо всех новинках конфереции первыми, так как подписаны на Android Live, так что следите за обновлениями. 😉

А может быть у вас есть идеи особых меропрятий для канала Android Live, которые посвящены этой конференции?

Можете поделиться в комментариях.
​​Сервисы для аналитики приложений
#library

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

Разработчики чаще используют Crashlytics, иногда добавляя сюда набор инструментов от Firebase. В целом, это хорошие инструменты, но ведь есть ещё ряд крутых сервисов, которые помогают анализировать приложения и их качество.
Ну а знания этих инструметов будет полезно в случае, если ваша роль в текущем проекте начинает выходить за рамки обычной разработки, или вы думаете о создании своего продукта. В любом случае, вы знаете, где взять их список, когда они понадобятся.

Весь список с детальным объяснением можно найти в этой статье, а мы рассмотрим несколько из описанных.

🔸продуктовая аналитика — нужна для получения информации о том, что конкретно делает пользователь в приложении. Сервисы — App Metrica и Firebase Analytics, Amplitude, Mixpanel.

🔸отправка пуш-уведомлений — полезны, если вы настраиваете группы пользователей, которым хотите их отправить. Сервисы — Firebase Cloud Messaging, AWS SNS, OneSignal.

🔸подключение платежей и подписок — очевидная и простая на первый взгляд вещь, но довольно непростая в реализации. Сервисы — Adapty, AppHud, RevenueCat.

🔸аналитика падений — наиболее близкая разработчикам вещь. Сервисы — AppMetrica, Firebase Crashlytics, Sentry.

Помните, что многие из описанных выше сервисов — платные, но многие из них дают бесплатную функциональность для маленьких продуктов.
​​Dependency Injection vs Service Locator
#patterns

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

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

Хорошее определение этих паттернов нашёл в этой статье.

🟢 если описать DI одним словом, то идеально подходит слово «отдавать». И в самом деле, при помощи DI мы просто даём нужные объекты другому объекту. В примере ниже классу House нужны объекты Door и Window, которые мы передаём ему в конструктор.

val window = Window()
val door = Door()
val house = House(window, door)


DI именно о том, что зависимости предоставляются нам кем-то. И нашему классу не важно, где этот кто-то данные зависимости берёт. Поэтому, мы и используем для DI конструктор, а не setter.

🔵 если мы описываем Service Locator одним словом, то идеально подходит слово «взять». Так, и есть: у нас есть какой-то класс (локатор, фабрика) у которого мы берём объекты, которые нужны нашему классу. В примере ниже, мы возьмём объект класса House напрямую из какого-то локатора и будем использовать его дальше.

val house = serviceLocator.get(House::class)

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

Современные библиотеки для внедрения зависимостей, такие как Dagger, Hilt, Koin, используют оба этих подхода в связке, хотя это и не всегда очевидно на первый взгляд. Но как мне кажется — это здорово, ведь каждый из них имеет свои плюсы, а подобное сосуществование уменьшает число недостатков.
​​Kotlin Flows — шпаргалка
#flow

Многие на своих проектах уже давно используют Flow в связке с Coroutines. На канале также было несколько постов о том, как лучше использовать эту связку и на что стоит обратить внимание.

Вот вам ещё одна небольшая заметка про Flow, где автор собрал в одну таблицу краткую информацию о них и о всех существующих типах Flow: в чём их разница, какие есть эквиваленты в RxJava, ссылки на документацию, примеры кода, где лучше применить их в Android.

Для тех, кто хочет шпаргалку сразу в pdf — вот ссылка, а сама статья с описание тут.
​​Как правильно передавать данные между Fragments?
#jetpack #fragment

Для передачи данных между Fragments есть несколько способов:
• использовать интерфейсы и callbacks;
• использовать Shared ViewModel;
• использовать setTargetFragment, правда он сейчас deprecated.

Но есть ещё один способ, который сейчас является самым удобным и основным. Начиная с версии Fragments 1.3.0-alpha04, FragmentManager имплементит FragmentResultOwner.

Дальше мы должны добавить ключ, который хотели бы слушать, и будем принимать Bundle с информацией. Для отправки результата надо использовать setFragmentResult с этим ключом, и добавить нужный нам Bundle.

Важно следить за уникальным использованием ключей, а также есть небольшие особенности при работе с childFragmentManager. Больше деталей и примеров кода можно найти тут.
​​Планируем задачи с WorkManager
#workmanager #jetpack #beginners

WorkManager — довольно важный компонент из Jetpack, который позволяет планировать задачи вне зависимости от того было ли закрыто ваше приложение или перезагружено устройство.
У него есть несколько преимуществ в сравнении с предшественниками: например, работа при определённом заряде батареи или Интернета, гибкие настройки для повторного запуска, интеграция с Coroutines и RxJava.

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

Ссылка на статью тут.

Были ли у вас проблемы с использованием WorkManager?
​​Лайфхаки для Firebase Remote Config
#firebase

Firebase Remote Config — это удобный сервис, который позволяет отправлять некий набор параметров через Firebase без участия вашего собственного сервера. Это удобно, ведь могут быть ситуации, когда у вас вообще нет сервера (например, в pet-проекте) или вам не просто добавить новую функциональность на ваш сервер.

Я активно использую инструменты Firebase, в том числе и этот. Нашёл статью, где автор описывает несколько хитростей для работы с Remote Config, возможно вы тоже найдёте для себя что-то полезное.

0️⃣Не забывайте о значениях по умолчанию в приложении. Об этом мало кто помнит, но вы можете установить значения по умолчанию для сервиса до тех пор, пока сервис не получить свой первый instance с Firebase. Это может быть полезно в случае каких-то проблем при получении данных. Сделать это можно двумя способами. Первый — это определение значений по умолчанию при получении определённой переменной, а второй — определить в самом config:
Firebase.remoteConfig.apply {
setDefaultsAsync(mapOf(
"key" to "default_value"
))
}


1️⃣Оберните получение данных в WorkManager. При использовании методов fetch или fetchAndActivate, вы можете получить исключение, например когда пользователь не имеет подключения к Интернет. Правильнее всего попробовать получить эти данные ещё раз, когда будет восстановлено соединение. Можно испльзовать Worker, где в конфигурации настроить запуск только при наличии соединения: setRequiredNetworkType(NetworkType.CONNECTED).

2️⃣Свяжите Remote Config с Cloud Functions. Довольно спорное решение, но оно может быть полезно, если вы хотите доставить обновления Config как можно быстрее. Идея в том, что вы отправляете пуш-уведомление пользователям при изменении Remote Config, делая текущее состояние данных неактуальными и заставляя FirebaseRemoteConfig получить данные как можно быстрее при следующем запуске приложения.
​​Автомиграции в Room
#room #jetpack

В версии Room 2.4.0-alpha01 добавили новую функциональность, которая значительно упрощает миграцию с одной версии базы данных на другую — автомиграции. До этой версии у вас было два пути при изменении схемы базы:
• писать миграцию вручную;
• заполнять базу данных заново, удаляя предыдущую версию базы.

Теперь появился гораздо более интересный способ. При повышении версии базы данных, вы можете указать параметр autoMigrations и добавить AutoMigration (from = 1, to = 2). Это всё, вы автоматически получите миграцию на новую версию. Более того, есть возможность комбинировать автомиграции и обычные миграции.

Но не всё так просто: подобная функциольность будет работать только тогда, когда вы делаете какие-то простые изменения в структуре базы, такие как: добавление новой колонки, изменение primary key, foreign key или индексов, изменение значений по умолчанию в колонке. Для случаев посложнее, например разделение таблицы на несколько, всё равно придётся писать ручную миграцию.

Кроме этого, добавили AutoMigrationSpec, которая может помочь Room сделать автомиграцию, если он не справляется сам. Там есть несколько аннотаций: DeleteTable, RenameTable, DeleteColumn, RenameColumn. В случае, если Room сам не сможет сделать миграцию, то вы получите exception. Это и будет являться признаком того, что надо использовать эти аннотации.

На мой взгляд — это отличная новость, которая избавит нас от написания большого числа лишнего кода в проекте. С нетерпением жду beta-версии.
​​Модуль навигации в Jetpack Compose
#jetpack #compose

Нашёл отличную статью, где автор приводит пример навигации при помощи Navigation Compose в приложении.

Получается, что навигация находится в отдельном модуле, который ответственнен только за это, а все остальные части приложения вообще не знают о том, что навигация реализована при помощи Navigation Component.

Статья получилась объёмной, но описанный подход заслуживает внимания. Ну и ссылка на проект, который там упоминается. В нём используется довольно свежий стек технологий, можно посмотреть, как ведут себя сырые библиотеки на готовом проекте.
​​Android Runtime: как работают Dalvik и ART
#theory

Android Runtime — одна из самых ключевых вещей в Android. Большинство слышали такие аббревиатуры как Dalvik, ART, JIT или AOT. Но далеко не все понимают, что они значат и как вообще работает среда выполнения Android.

В статье или видео можно найти детальную информацию об этом. Для начала рассматривается вообще понятие среды выполнения, а далее сравниваются все современные (и не очень) среды.

Подобная информация полезна для общего понимания того, из чего состоит приложение и как оно работает, ну и будет полезна при прохождении собеседований.
​​Оптимизация кастомных View: Live-coding сессия — Евгений Зубков
#youtube

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

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

Сделаем это с нашим экспертом, Евгением Зубковым из компании Revolut. Евгений — разработчик с 10-летним опытом разработки под Android и автор статей.

Ну а мы на живом примере обсудим:
👉 на каких этапах происходит больше всего просадок в производительности;
👉 чего не стоит делать в определённых методах;
👉 как понять, что ваша View работает с тормозами;
👉 какие механизмы отрисовки View стоит использовать, а какие нет;
👉 ну и конечно же ответим на все ваши вопросы.

Стрим состоится 5 мая в 18:30 по МСК на YouTube-канале Android Live, ссылка тут. И конечно предлагаю вам подписаться на YouTube-канал, чтобы вы могли получать уведомления о новых стримах и трансляциях. ✌🏻
​​Опыт перехода с Mac на Ubuntu
#offtop

Любопытная статья, которая описывает опыт Android-разработчика при переходе с Macbook на кастомный компьютер с Ubuntu.

Основным моментом из-за которого он запланировал переход — неготовность платить раз в несколько лет за покупку нового Macbook. Конфигурация его компьютера здесь.

В результате он выделил пару минусов:
• огромный компьютер, который сложно транспортировать;
• баги подключения bluetooth-наушников к некоторым приложениям;
• горячие клавиши, которые нужно выучить заново.

В остальном — только плюсы:
• более шустрая работа git;
• более мощный терминал для работы;
• ускоренная сборка билдов;
• довольно низкая цена за итоговый компьютер.

Статья не изобилует различными сравнениями и бенчмарками, но личное мнение всегда интересно. Интересно, как будет сравниваться его компьютер с новыми чипами от Apple, ведь стабильной версии Android Studio вроде как нет (но есть alpha).

А был ли у вас опыт перехода с одной операционной системы на другой? Какие ощущения?. Будет интересно, если расскажите в комментариях.
2025/08/28 19:32:42
Back to Top
HTML Embed Code: