Academy Minsk News & Announcements
Самые интересные новости, видео с конференций из Android мира. Анонсы митапов, важных и полезных конференций от сообщества Android Academy Minsk. Обсудить материал вы можете в чате: https://t.me/androidacademyminsk
إظهار المزيد- المشتركون
- التغطية البريدية
- ER - نسبة المشاركة
جاري تحميل البيانات...
جاري تحميل البيانات...
ExoPlayer
в вашем приложении для Android.
Основные советы:
1️⃣ Для коротких видео не стоит использовать HLS, DASH, а лучше сразу идти с MP4
2️⃣ SimpleCache стоит создавать на бэкграунд треде, потому как могут привести к ANR. Стоит использовать URL в качестве ключа для видео из сети
3️⃣ Для предзагрузки видео можно использовать DownloadManager. Для предварительной загрузки адаптивных потоков можно использовать DownloadManager
в сочетании с DownloadHelper
, который упрощает эту работу
4️⃣ Контроль загрузки — это механизм, позволяющий управлять загрузками. Говоря простым языком, он решает следующие вопросы:
📌 Хватит ли нам данных для начала воспроизведения?
📌 Должны ли мы продолжать загрузку дополнительных данных?
🔸 Здесь на сцену выходят различные параметры вида bufferForPlaybackMs, bufferForPlaybackAfterRebufferMs, minBuffer & maxBuffer
5️⃣ Осталось еще настроить адаптивны битрейт и потом заняться оптимизацией рендеринга видео
Все детали вы можете прочитать в статье. Статья написано очень интересно, так что всем советую 🔥In this article, I will share practical tips, supported by production data, on how to improve video playback from different perspectives.
GlobalScope.launch { throw Exception() }.join()
Все ошибки перед попаданием Uncaught exception handler проходят через platformExceptionHandlers
. На андроиде в platformExceptionHandlers
добавляется Coroutine exception handler для обхода бага на андроиде 8. Если Coroutine exception handler из platformExceptionHandlers
бросит ExceptionSuccessfullyProcessed
, то ошибка не попадет в Uncaught exception handler.TL;DR Все ошибки перед попаданием UEH проходят через platformExceptionHandlers. На андроиде в platformExceptionHandlers добавляется CEH для обхода бага на андроиде 8. Если CEH из...
Monads
и как они могут помочь при работе с ошибками в приложении.
В одной из статей Роман Элизаров ясно указывает, что исключения в Kotlin следует использовать для обработки логических ошибок, то есть ошибок разработчика, и не стоит перехватывать неожиданные исключения или RuntimeExceptions
.
В итоге у нас появляется такое понятие как результирующая монада. Что такое Monad
можно узнать из википедии. Автор предлагает использовать отдельную библиотеку Kotlin-Result, которая имеет достаточно богатое API для работы с результирующей монадой.
Раскрывать монаду стоит на уровне ViewModel
, чтобы на UI явно передавать правильное состояние.A minimal, responsive and feature-rich Jekyll theme for technical writing.
data class Subscription( // class is unstable
val id: Int, // stable
val planName: String, // stable
val renewalOn: LocalDate // unstable
)
🔸 Свойство renewalOn
нестабильно, поскольку java.time.LocalDate
из стандартной библиотеки Java, которая не имеет зависимости от компилятора Compose
🔸 Далее если рассмотреть пример:
var state by mutableStateOf(Subscription(
id = 1,
planName = "30 days",
renewalOn = LocalDate.now().plusDays(30)
))
@Composable
fun SubscriptionComposable(input: Subscription) {
...
}
🔸 Составная функция с входным параметром этого нестабильного класса не определялся как skippable
, и значит всегда будет рекомпозироваться
🔸 Компилятор Jetpack Compose 1.5.4 и выше имеет возможность включить strong skipping mode
, который всегда генерирует логику пропуска независимо от стабильности входных параметров
🔸 В режиме strong skipping есть два способа определить, изменился ли входной параметр по сравнению с предыдущей композицией:
📌 Если класс стабилен, он использует структурное равенство .equals()
📌 Если класс нестабилен, он использует ссылочное равенство ===
🔸 После включения режима строгого пропуска в проекте компонуемые объекты, использующие нестабильный класс Subscription
, не будут перекомпоновываться, если экземпляр такой же, как в предыдущей композиции
🔸 Чтобы не делать рекомпоновку необходимо выставить аннотацию:
@Immutable
data class Subscription( // stable
val id: Int, // stable
val planName: String, // stable
val renewalOn: LocalDate // unstable
)
🔸 В этом случае будет использовано equals()
на экзпемлярах
🔸 Для классов, которые не являются частью вашей кодовой базы, раньше советовали, что единственный способ стабилизировать их — это обернуть класс классом, который является частью вашей кодовой базы, и вместо этого аннотировать этот класс как @Immutable
🔸 Рассмотрим пример, в котором у вас есть составной объект, который напрямую принимает параметр java.time.LocalDate
:
@Composable
fun LatestChangeOn(updated: LocalDate) {
// ...
}
🔸 Вы можете включить файл конфигурации стабильности, который может содержать классы или шаблоны классов, которые компилятор Compose будет считать стабильными
🔸 Чтобы включить его, добавьте файл stabilityConfigurationFile
в конфигурацию composeCompiler
:
composeCompiler {
...
// Set path of the config file
stabilityConfigurationFile = rootProject.file("stability_config.conf")
}
🔸 И добавьте в файл значение:
java.time.LocalDate
java.time.*
🔸 Еще одним преимуществом сильного пропуска является то, что он запоминает все лямбды, используемые в композиции
🔸 Раньше причиной рекомпозиции могли быть лямбды, использующие нестабильный класс, например ViewModel
. Одним из распространенных обходных путей было запоминание лямбда-функций
🔸 В итоге можно в Compose сделать так без remember
как привыкли:
Screen(
removeItem = { id -> viewModel.removeItem(id) }
)
Master strong skipping, annotations, configuration file, and more to optimize stability.
asserts
и там и там одно понятие, поэтому в понимание это будет неважно.Меня зовут Александр Чекунков, я - Android-разработчик в СБЕРе. Занимаюсь разработкой CSI-опросов в мобильном приложении “Сбер”. Я несу ответственность за функционал, который используют бизнес-команды...
CoroutineContext
, а именно обсудим Dispatchers
и все что с ними связано
Основная цель встреч – это получить и закрепить знания, а также неформальное общение.
Детали встречи:
Дата – 17 июля, в среду в 19 вечера
Место – г. Минск прт. Победителей, д. 110, БЦ Ривьера Плаза (вход со стороны прт. Победителей), 4 этаж – офис Тинькофф
Продолжительность – 1+ час (по желанию)
Тема – Kotlin Coroutines
Жду встречи ❤️
P.S. Если не сможете найти, то пишите мне в телеграмме @PavelShaCompound View
📌 понимание Single-Activity
📌 Важно ориентироваться как в XML, так и в Jetpack Compose
🔸 Jetpack Compose — это сложно, и работодатели это понимают, поэтому для джуниоров может быть достаточно и базовых знаний
📌 Погружение в архитектуру — чем глубже, тем лучше
🔸 Джуну важно ориентироваться в том, как строится архитектура, как взаимосвязаны слои, знать шаблоны MVVM и MVI, уметь работать с ViewModel
, понимать, как работает внедрение зависимостей Dependency injection (как минимум с Koin, но лучше с Dagger)
📌 Функциональное программирование — must have хотя бы на базовом уровне
🔸 Джун должен хорошо знать Kotlin и Java, разбираться в синтаксисе и иметь навыки оптимизации кода. Я бы в первую очередь вот на эти вещи делал уклон, а с опытом помогал ему писать большее сложные системы. Но начал с простых вещей
📌 Coroutines нужен работодателям чаще, чем RxJava, но джуниорам достаточно и базового знания многопоточности.
🔸 Джуниору важно понимать принципы многопоточности и ориентироваться, что происходит хотя бы в чужом коде: как выполняется вызов, в какой момент элемент выпадает из потока и так далее
📌 Знание Gradle — плюс при трудоустройстве
🔸 Хорошо, если джуниор умеет подключать модули, создавать билд-варианты с релизными сборками, добавлять подписи, находить ошибки в логе Gradle и исправлять их, объявлять плагины и зависимости.
📌 Знание многомодульности пригодится в крупных проектах
📌 CI/CD джуниорам не нужен, но знание методологии будет плюсом
🔸 Чтобы выделиться, джуниор может сделать проект в портфолио и настроить для него CI/CD в Git
📌 Знания по аналитике могут пригодиться в студии, но не в большой компании
🔸 В большинстве компаний Android-разработчику не пригодятся знания аналитики, но пару вопросов по теме на собеседовании задать могут
📌 Джуниору достаточно поверхностного знания Service
🔸 На собеседовании могут спросить, что это за технология и какие у неё ограничения, какие типы сервисов существуют
📌 Софтскилы крайне важны для джуниора
🔸 Лидирует в списке софтскилов умение быстро погружаться в проект и понимать, что в нём происходит
🔸 Также в списке важных софтскилов:
📌 адекватность, отсутствие пассивной агрессии
📌 искренняя заинтересованность в работе и желание обучаться
📌 умение общаться — при этом душой компании быть необязательно, достаточно просто уживаться в коллективе
Далее автор рассказывает про какой опыт необходим и как нанимают джунов, какие механики используются: тестовое задание или еще что-то.Команда Яндекс Практикума провела исследование и готова рассказать, как обстоят дела в найме начинающих Android-разработчиков : какие навыки требуются джуниорам для трудоустройства, о чём их...
Observer
с помощью корутин.
Из такого:
interface Observable {
fun addListener(owner: Any?, listener: (Event) -> Unit)
fun removeListener(owner: Any?)
}
Автор трансформировал в такое:
interface AutoDetachObservable {
fun listen(
scope: CoroutineScope,
listener: (Event) -> Unit
): Job
}
С реализацией:
fun listen(
scope: CoroutineScope,
listener: (Event) -> Unit
): Job{
val id = generateUniqueId()
val job = scope.launch{ listenerRegistry[id] = listener }
job.invokeOnCompletion{ listenerRegistry.remove(id) }
return job
}
People talk a lot about so-called design patterns (usually referencing those made in the famous book...
view.setOnСlickListener(null)
🔸 Запускается код и он не работает. Причин может быть много разных почему так. Как можно решить проблему? Есть много разных способов, но помогут два самых главных навыка разработчика — умение читать чужой код и разбираться в нем + умение дебажить
🔸 Какие есть виды дебага:
📌 Просмотр исходного кода
📌 Дебаг логгированием
🔸 В андроиде, например, уже есть много системных логов, но также можно добавлять свой вывод, как просто через system.out.println("my_text")
📌 Дебаг по брейкпоинтам
🔸 Это вид отладки, когда проверяем работу программы по заданными брейкпоинтам. При этом конкретно Android Studio даёт богатое количество возможностей при данном виде отладки
👉 можем посмотреть какие значения в каких переменных проставлены
👉 проставить значение в переменную и пустить выполнение программы дальше
👉 также можем настраивать conditional breakpoints
📌 Дебаг профилированием
📌 Дебаг с помощью Layout Inspector (актуален только для приложений с UI)
🔸 В описанной проблеме с неработающим занулением клик лисенера в первую очередь должный зайти в исходный код компонента и посмотреть как он работает
🔸 У компонента переопределен метод setOnClickListener.
И даже если передаем в него null
, он всё равно вешает клик листенер
2️⃣ Пример №2
🔸 Исходные условия всё те же, экранчики приложения строятся из компонентов дизайн-системы как из кирпичиков. Открываем приложение и видим, что иконка как-то сильно прижалась к верху
🔸 Используется компонент, который называется AlertView
. Так вот из интересного — в компонент AlertView
никаких изменений не вносилось, а ошибка возникла
🔸 Настройка выглядит следующим образом:
data class AlertViewModel(
val icon: IconElementModel,
val texts: Texts = Texts.None,
val buttons: Buttons = Buttons.None,
): Serializable
🔸 В AlertViewModel
ничего странного нет, но внутри себя использует IconElementModel
для отображения иконки, с которой как раз у проблема:
data class IconElementModel constructor(
override val icon: Image? = null,
@Transient override val horizontalPaddingNew: HorizontalPadding,
@Transient override val verticalPadding: VerticalPadding
): Serializable
🔸 Видим, что вертикальный отступ действительно отсутствует, как и ожидали. Получается, что нашли корень проблемы и теперь знаем как его фиксить
🔸 Но почему оно сломалось, если изменений не вносилось?
🔸 В итоге оказалось, что на это поведение повлияло повышение targetSdk
. А повлияло потому, что при передаче модельки, опирались на внутреннюю реализацию SDK, а именно на кейс, когда передача объекта происходила по ссылке, а не через реальную сериализацию и десериализацию
Остался еще один пример, где не выставили LayoutManager
для RecyclerView
Смог автор на примерах вас убедить?Привет! Меня зовут Абакар и я работаю главным тех лидом в Альфа Банке. Меня часто посещает вопрос — «А какой навык всё-таки самый полезный для разработчика?». Понятное дело, что ответ на этот вопрос...
Приветствую всех! На связи Михаил Емельянов, руководитель Android-направления в RuStore. За последние два года наш проект достиг впечатляющих результатов: более 50 миллионов установок, около 40 тысяч...
تسمح خطتك الحالية بتحليلات لما لا يزيد عن 5 قنوات. للحصول على المزيد، يُرجى اختيار خطة مختلفة.