Немного изменений в демке. Времени пока не так много на нее, увы.
На полноценную часть про Compose не тянет, но пару интересных изменений о которых хочется рассказать все же есть.
1. Звучит как шутка, но наконец-то победил SwipeRefresh и сам свайп теперь работает из любой части макета, без краша. Пришлось добавить во все нужные функции ниже корневой модификатор verticalScroll(rememberScrollState()). Если добавлять в корневой Column - краш!
2. Теперь экземпляр вьюмодели получаем прямиком из Composable-функции через hiltViewModel()
Эта функция доступна в отдельной либе androidx.navigation:navigation-compose:2.4.0-alpha04
Кстати, на более свежую версию пока обновляться не советую. Вся навигация ломается на хрен! Начинается бесконечный recompose сплеш-скрина.
3. Убрал не нужные элементы, вроде вложенных Column. Стало немного чище.
Из интересного еще вот что.
hiltViewModel() стоит использовать если у вас есть навигация через NavComponent и инжекты через Hilt. В MainScreen эта функция как раз и выручает, а если будем использовать обычный метод viewModel() - угадайте что? Правильно! Краш.
Хотя в SplashScreen прекрасно работает и viewModel(), но на всякий случай решил использовать и там hiltViewModel(), для консистентности.
Код, как обычно, здесь: https://github.com/Djangist/ComposeArchSample
На полноценную часть про Compose не тянет, но пару интересных изменений о которых хочется рассказать все же есть.
1. Звучит как шутка, но наконец-то победил SwipeRefresh и сам свайп теперь работает из любой части макета, без краша. Пришлось добавить во все нужные функции ниже корневой модификатор verticalScroll(rememberScrollState()). Если добавлять в корневой Column - краш!
2. Теперь экземпляр вьюмодели получаем прямиком из Composable-функции через hiltViewModel()
Эта функция доступна в отдельной либе androidx.navigation:navigation-compose:2.4.0-alpha04
Кстати, на более свежую версию пока обновляться не советую. Вся навигация ломается на хрен! Начинается бесконечный recompose сплеш-скрина.
3. Убрал не нужные элементы, вроде вложенных Column. Стало немного чище.
Из интересного еще вот что.
hiltViewModel() стоит использовать если у вас есть навигация через NavComponent и инжекты через Hilt. В MainScreen эта функция как раз и выручает, а если будем использовать обычный метод viewModel() - угадайте что? Правильно! Краш.
Хотя в SplashScreen прекрасно работает и viewModel(), но на всякий случай решил использовать и там hiltViewModel(), для консистентности.
Код, как обычно, здесь: https://github.com/Djangist/ComposeArchSample
GitHub
GitHub - Djangist/ComposeArchSample
Contribute to Djangist/ComposeArchSample development by creating an account on GitHub.
Проблема с минификацией в com.android.tools.build:gradle:4.2.2
Не знаете как провести рабочий день? Скучно пилить новые бизнес-фичи?
Можно, например, попытаться понять в чем заключается проблема
java.lang.IllegalArgumentException: Method return type must not include a type variable or wildcard
с API-методом в Retrofit, который возвращает обычный Single<ResponseDto>.
Оказывается, в версии 4.2.2 плагина com.android.tools.build:gradle намудрили что-то с минификацией и он выкашивает dto-объекты ответа, которые не используются.
Суть проблемы: https://github.com/square/retrofit/issues/3588
Распространите коллегам, чтобы были в курсе, а то минус день-другой обеспечены.
Не знаете как провести рабочий день? Скучно пилить новые бизнес-фичи?
Можно, например, попытаться понять в чем заключается проблема
java.lang.IllegalArgumentException: Method return type must not include a type variable or wildcard
с API-методом в Retrofit, который возвращает обычный Single<ResponseDto>.
Оказывается, в версии 4.2.2 плагина com.android.tools.build:gradle намудрили что-то с минификацией и он выкашивает dto-объекты ответа, которые не используются.
Суть проблемы: https://github.com/square/retrofit/issues/3588
Распространите коллегам, чтобы были в курсе, а то минус день-другой обеспечены.
GitHub
Method return type must not include a type variable or wildcard · Issue #3588 · square/retrofit
Using com.squareup.retrofit2:retrofit:2.9.0 After upgrading gradle plugin from com.android.tools.build:gradle:4.1.3 to com.android.tools.build:gradle:4.2.2 I'm getting following error when ...
Вышел Compose 1.0!
C одной стороны прекрасная новость и можно активнее учить основы, пробовать внедрять какие-то кусочки UI (без фанатизма), а с другой привязки разных библиотек к Compose все еще в альфа, бета-версиях, что не очень.
Кстати, обновил демо проект на версию 1.0.
Немного радости от Compose Team:
https://www.youtube.com/watch?v=kLA1QwDjioc
C одной стороны прекрасная новость и можно активнее учить основы, пробовать внедрять какие-то кусочки UI (без фанатизма), а с другой привязки разных библиотек к Compose все еще в альфа, бета-версиях, что не очень.
Кстати, обновил демо проект на версию 1.0.
Немного радости от Compose Team:
https://www.youtube.com/watch?v=kLA1QwDjioc
YouTube
Announcing Jetpack Compose 1.0
Today, we're launching version 1.0 of Jetpack Compose, Android's modern, native UI toolkit to help you build better apps faster. It's stable, and ready for you to adopt in production.
Our team has been developing Compose in the open with feedback and participation…
Our team has been developing Compose in the open with feedback and participation…
Любопытная библиотечка для дебаггинга на самом девайсе.
Показывает логи HTTP-запросов, собирает краши приложения, а еще можно смотреть shared preferences и подправлять на нужное значение для отладки.
Вообщем, может пригодится в повседневной работе.
Ссылка на либу: https://github.com/mocklets/pluto
Показывает логи HTTP-запросов, собирает краши приложения, а еще можно смотреть shared preferences и подправлять на нужное значение для отладки.
Вообщем, может пригодится в повседневной работе.
Ссылка на либу: https://github.com/mocklets/pluto
GitHub
GitHub - androidPluto/pluto: Android Pluto is a on-device debugging framework for Android applications, which helps intercept Network…
Android Pluto is a on-device debugging framework for Android applications, which helps intercept Network calls, capture Crashes & ANRs, manipulate application data on-the-go, and much more....
Кстати, а вы обновили студию до Arctic Fox?
Она уже где-то неделю в stable. Я обновился и работаю в Arctic Fox и над старым (основным рабочим) проектом и над новыми обучающими с Compose на борту.
Полет пока нормальный, но есть нюансы:
1. Аккуратнее с R8 в релизных билдах. Теперь он более рьяно выпиливает неиспользуемые классы. Недавний пример есть на канале.
2. Выпилена инструкция compile и ее производные. Теперь только implementation.
3. Теперь AGP 7.0 (Android Gradle Plugin) требует Gradle 7.0 и Java 11.
4. Новый Layout Inspector теперь позволяет строить дерево composable-функций, смотреть как они отрисованы, просматривать параметры и т.д. - довольно удобно!
5. Preview для Compose. Его можно настроить довольно гибко, добавляя по нескольку превьюшек для одной функции, включать системный интерфейс, фоны и прочее. Здесь пока есть проблемы с отрисовкой (превью иногда не работает), но думаю допилят в ближайших обновлениях.
6. Теперь можно вытащить sqlite базу к себе на диск и выбрать при экспорте нужный формат. Не то чтобы вау-новость, но теперь можно быстрее вытаскивать БД и смотреть проблемы с таблицами, хотя и раньше можно было.
7. И самое любопытное для меня. В AGP 7.0 убрали build cache, при этом заявляют, что скорость сборки не просядет. Убрали задачу cleanBuildCache, свойства android.enableBuildCache, android.buildCacheDir.
Видосик: https://www.youtube.com/watch?v=-8tSZr7iMcw
Она уже где-то неделю в stable. Я обновился и работаю в Arctic Fox и над старым (основным рабочим) проектом и над новыми обучающими с Compose на борту.
Полет пока нормальный, но есть нюансы:
1. Аккуратнее с R8 в релизных билдах. Теперь он более рьяно выпиливает неиспользуемые классы. Недавний пример есть на канале.
2. Выпилена инструкция compile и ее производные. Теперь только implementation.
3. Теперь AGP 7.0 (Android Gradle Plugin) требует Gradle 7.0 и Java 11.
4. Новый Layout Inspector теперь позволяет строить дерево composable-функций, смотреть как они отрисованы, просматривать параметры и т.д. - довольно удобно!
5. Preview для Compose. Его можно настроить довольно гибко, добавляя по нескольку превьюшек для одной функции, включать системный интерфейс, фоны и прочее. Здесь пока есть проблемы с отрисовкой (превью иногда не работает), но думаю допилят в ближайших обновлениях.
6. Теперь можно вытащить sqlite базу к себе на диск и выбрать при экспорте нужный формат. Не то чтобы вау-новость, но теперь можно быстрее вытаскивать БД и смотреть проблемы с таблицами, хотя и раньше можно было.
7. И самое любопытное для меня. В AGP 7.0 убрали build cache, при этом заявляют, что скорость сборки не просядет. Убрали задачу cleanBuildCache, свойства android.enableBuildCache, android.buildCacheDir.
Видосик: https://www.youtube.com/watch?v=-8tSZr7iMcw
YouTube
What's new in Android Studio Arctic Fox
Get an overview of what tools and features are available in Android Studio Arctic Fox and the new updates and requirements to Android Gradle Plugin 7.0.
New features:
•Compose support (preview, interactive preview, layout inspector)
•Accessibility Scanner…
New features:
•Compose support (preview, interactive preview, layout inspector)
•Accessibility Scanner…
Небольшая quiz-задачка по Compose, которая прекрасно раскрывает суть recomposing (рекомпозиции) - одной из основных концепций нового декларативного UI.
Грубо говоря, суть ее в том, что элемент UI будет обновлен (отрисован повторно), если изменится его состояние, а если часть UI остается в прежнем состояние, то Compose просто возьмет уже закешированное (ранее уже отрисованное состояние). Таким образом меняется лишь часть UI, а не все дерево целиком, как обычно происходит в xml.
У нас есть такой код:
Грубо говоря, суть ее в том, что элемент UI будет обновлен (отрисован повторно), если изменится его состояние, а если часть UI остается в прежнем состояние, то Compose просто возьмет уже закешированное (ранее уже отрисованное состояние). Таким образом меняется лишь часть UI, а не все дерево целиком, как обычно происходит в xml.
У нас есть такой код:
@Composable
fun Foo() {
Log.d(TAG,"recompose Foo")
var text by remember { mutableStateOf("") }
Log.d(TAG,"recompose Foo text")
Button(onClick = { text = "$text\n$text" }) {
Log.d(TAG,"recompose Button's lambda")
Text(text)
}
}Какой текст выведется в лог если несколько раз нажать на кнопку?
Final Results
33%
recompose Foo, recompose Foo, recompose Foo
22%
recompose Foo text, recompose Foo text, recompose Foo text
44%
recompose Button's lambda, recompose Button's lambda, recompose Button's lambda
0%
Ни один из перечисленных - напишу свой в комментарий
И так, друзья.
Правильный ответ на наш квиз - вариант №3: recompose Button's lambda, recompose Button's lambda, recompose Button's lambda
Некоторые из вас ответили именно так!
Поздравляю!
Вся штука в переменной:
Это утверждение можно легко проверить, изменив наш код, и при клике подставив в text статичное значение:
Правильный ответ на наш квиз - вариант №3: recompose Button's lambda, recompose Button's lambda, recompose Button's lambda
Некоторые из вас ответили именно так!
Поздравляю!
Вся штука в переменной:
var text by remember { mutableStateOf("") }
При клике она меняется и таким образом меняется состояние элемента Text и скоуп кнопки, что заставляет Compose отрисовать ее с новым состоянием и кнопка становится все больше и больше.Это утверждение можно легко проверить, изменив наш код, и при клике подставив в text статичное значение:
Button(onClick = { text = "123" }) {
Log.d(TAG,"recompose Button's lambda $text")
Text(text)
}
Тогда при первом клике кнопка отобразит один раз наш текст 123 и далее стейт (состояние) при каждом клике уже меняться не будет.Еще немного про состояние (states) в Compose, но в контексте нашего демо-приложения:
https://github.com/Djangist/ComposeArchSample
Кто внимательно следит за постами, возможно помнит, что недавно наконец-то заработал SwipeRefresh, но если сделать свайп до конца - данные не обновляются.
Хотя в репозитории уже есть случайное генерирование температуры для моделек.
Чего же нам не хватает?
1. У нас есть вьюмодель, с данными, которые хранятся в StateFlow.
2. Мы подписались на эти данные и в случае их изменения, обновим UI
Вот наша главная composable-функция:
А не хватает нам всего лишь одного метода: collectAsState(),который уже добавлен как расширение для StateFlow.
Пара изменений в коде и данные по свайпу стали обновляться:
В описании к методу все наглядно (см скрин).
Каждое новое значение в StateFlow теперь будет приводить к recomposition, а это то, что нам и нужно!
Выглядит пока что это все неплохо. Поток данных можно довольно просто контролировать, обновляя лишь нужные кусочки UI.
Осталось добавить какой-то механизм, который будет управлять разными состояниями (например, Reducer в качестве части MVI-архитектуры/UI-паттерна) для полной красоты и усложнить наш пример, дабы посмотреть какие-то сложные кейсы и сложные состояния.
https://github.com/Djangist/ComposeArchSample
Кто внимательно следит за постами, возможно помнит, что недавно наконец-то заработал SwipeRefresh, но если сделать свайп до конца - данные не обновляются.
Хотя в репозитории уже есть случайное генерирование температуры для моделек.
Чего же нам не хватает?
1. У нас есть вьюмодель, с данными, которые хранятся в StateFlow.
2. Мы подписались на эти данные и в случае их изменения, обновим UI
Вот наша главная composable-функция:
@Composable
fun MainScreen() {
val viewModel: MainViewModel = hiltViewModel()
val mainWeather = viewModel.mainWeatherData.value
val daysWeather = viewModel.daysWeatherData.value
val hoursWeather = viewModel.hoursWeatherData.value
ShowWeather(
viewModel,
mainWeather,
daysWeather,
hoursWeather
)
}
А не хватает нам всего лишь одного метода: collectAsState(),который уже добавлен как расширение для StateFlow.
Пара изменений в коде и данные по свайпу стали обновляться:
val viewModel: MainViewModel = hiltViewModel()
val mainWeather = viewModel.mainWeatherData.collectAsState()
val daysWeather = viewModel.daysWeatherData.collectAsState()
val hoursWeather = viewModel.hoursWeatherData.collectAsState()
ShowWeather(
viewModel,
mainWeather.value,
daysWeather.value,
hoursWeather.value
)
В описании к методу все наглядно (см скрин).
Каждое новое значение в StateFlow теперь будет приводить к recomposition, а это то, что нам и нужно!
Выглядит пока что это все неплохо. Поток данных можно довольно просто контролировать, обновляя лишь нужные кусочки UI.
Осталось добавить какой-то механизм, который будет управлять разными состояниями (например, Reducer в качестве части MVI-архитектуры/UI-паттерна) для полной красоты и усложнить наш пример, дабы посмотреть какие-то сложные кейсы и сложные состояния.
Еще никогда не было так просто настроить CI/CD для Android-приложения.
После появления Github Actions (у Gitlab есть аналогичная штука) это можно сделать за три минуты!
Кайф!
Пост: https://proandroiddev.com/continuous-integration-delivery-for-android-with-github-actions-part-1-b232ed2b1740
После появления Github Actions (у Gitlab есть аналогичная штука) это можно сделать за три минуты!
Кайф!
Пост: https://proandroiddev.com/continuous-integration-delivery-for-android-with-github-actions-part-1-b232ed2b1740
Medium
“Continuous Integration/Delivery” for Android with GitHub Actions — Part 1
Dear developers, In this article I will show you how to automate the test execution and build of your Android app…
Забавный баг в Android Studio Arctic Fox (хотя, возможно, был и раньше).
Если остановить выполнение задачи (хорошо воспроизводится на задаче по сборке проекта), нажав на крестик (скрин 1), после остановки задачи, зеленая кнопка для запуска сборки проекта повторно не появляется (скрин 2) 🙂
Нужно запустить, например, Clean, чтобы кнопка появилась повторно.
Если остановить выполнение задачи (хорошо воспроизводится на задаче по сборке проекта), нажав на крестик (скрин 1), после остановки задачи, зеленая кнопка для запуска сборки проекта повторно не появляется (скрин 2) 🙂
Нужно запустить, например, Clean, чтобы кнопка появилась повторно.
Прекрасный доклад по модуляризации на посмотреть вечером, который покрывает и многие темы разработки ПО в более широком смысле!
https://www.youtube.com/watch?v=oAQlKiF91Ks
Кстати, на канале конференции еще множество интересных видосов.
https://www.youtube.com/watch?v=oAQlKiF91Ks
Кстати, на канале конференции еще множество интересных видосов.
YouTube
Степан Гончаров — Абсолютная модуляризация
Подробнее о конференции Mobius: https://jrg.su/ojGU3B
— —
. . .
Что, если вам больше не нужно быть Gradle экспертом, чтобы проектировать, поддерживать и эффективно масштабировать современные многомодульные Android-приложения, но при этом сразу же получить…
— —
. . .
Что, если вам больше не нужно быть Gradle экспертом, чтобы проектировать, поддерживать и эффективно масштабировать современные многомодульные Android-приложения, но при этом сразу же получить…
А вот и часть 3 хаотичного изучения Coroutines от RMR.
В новом выпуске ребята разобрали:
- Для чего был нужен SingleLiveEvent
- Как его приготовить без LiveData
- Channel
- О трате ресурсов в бекграунде
- buffer, conflate, flowOn, shareIn
- WhileSubscribed
- и многое другое.
Получился очень полезный выпуск.
В новом выпуске ребята разобрали:
- Для чего был нужен SingleLiveEvent
- Как его приготовить без LiveData
- Channel
- О трате ресурсов в бекграунде
- buffer, conflate, flowOn, shareIn
- WhileSubscribed
- и многое другое.
Получился очень полезный выпуск.
YouTube
Coroutines. Хаотичное изучение. Часть 3
Третья часть "хаотичного изучения" Kotlin Coroutines о том как безопасно слушать из UI. 🧔🏻
Зашли издалека:
- Для чего был нужен SingleLiveEvent 📟
- Как его приготовить без LiveData 🔫
- Channel (кажется это спойлер 😆)
- О трате ресурсов в бекграунде 🔦
- buffer…
Зашли издалека:
- Для чего был нужен SingleLiveEvent 📟
- Как его приготовить без LiveData 🔫
- Channel (кажется это спойлер 😆)
- О трате ресурсов в бекграунде 🔦
- buffer…
Пост 20. "Паттерн" репозиторий.
Многие уже знают о таком понятии как репозиторий. Однако, я все равно часто наблюдаю в коде проектов некое непонимание как правильно его "готовить".
Давайте разбираться.
В доках Гугла часто можно встретить примеры в которых во ViewModel напрямую ижектят репозитории, что мягко говоря, не очень правильно.
На самом деле, ViewModel или Presenter (смотря что используете) не должен ничего знать о репозиториях. Обычно с репой работает UseCase или Interactor. И именно он инжектится во ViewModel.
Но давайте о главном.
Что же такое репозиторий (Repository)?
Репозиторий можно рассматривать как коллекцию, которая работает с какой-либо моделью данных.
И только с одной моделью.
Это важно.
Если хочется работать с несколькими моделями, то самое правильное - это создать на каждую модель свой отдельный репозиторий.
Тут не стоит лениться - в дальнейшем будет меньше проблем.
Обычно репозиторий возвращает вам список моделей или конкретную модель, кеширует какие-либо локальные данные и возвращает эти данные из кеша и вот это вот все. Но в нем нет и не должно быть НИКАКОЙ другой логики (особенно бизнес-логики). Чем он тупее - тем лучше. Положили модель куда-то, отдали модель.
Теперь немного про слои.
Самые первые реализации Clean Arctitecture под Android делили слои репозиториев так:
1. Интерфейс репозитория мы помещаем на уровне domain.
2. Реализацию (класс, наследующий интерфейс репозитория) на уровне data.
3. UseCases / Interactors инжектит в конструктор именно интерфейс репозитория, а не реализацию! Это тоже очень важно. Реализацию подставит DI-фреймворк.
Сейчас же, когда проекты стали делить на features (фичи), а еще большие проекты на features в отдельных модулях, принцип разделения на слои остался прежним (в каждом модуле фичи своя структура domain - data - presentation).
Еще стоит отдельно упомянуть, что репозитории могут реализовывать разные DataSource (обычно инжектится в конструктор), например:
Для чего это нужно?
Ну например, один заинжекченный репозиторий работает с локальным кешем данных, а другой всегда получает данные из сети. Интерфейс репозитория один и тот же, но за счет подстановки нужной реализации DataSource в конструктор поведение меняется.
При этом сохраняется исходный интерфейс, что всегда удобно во время тестирования или рефакторинга.
И такое на практике встречается частенько.
По большому счет это все основы, которые стоит четко для себя понимать при работе с репозиторием.
Главное следуем картинке ниже, чтобы Dependency Rule не нарушался и будет вам счастье.
Кстати, стоит ли отдельно рассказать про этот самый Dependency Rule?
Пишите в комменты.
Многие уже знают о таком понятии как репозиторий. Однако, я все равно часто наблюдаю в коде проектов некое непонимание как правильно его "готовить".
Давайте разбираться.
В доках Гугла часто можно встретить примеры в которых во ViewModel напрямую ижектят репозитории, что мягко говоря, не очень правильно.
На самом деле, ViewModel или Presenter (смотря что используете) не должен ничего знать о репозиториях. Обычно с репой работает UseCase или Interactor. И именно он инжектится во ViewModel.
Но давайте о главном.
Что же такое репозиторий (Repository)?
Репозиторий можно рассматривать как коллекцию, которая работает с какой-либо моделью данных.
И только с одной моделью.
Это важно.
Если хочется работать с несколькими моделями, то самое правильное - это создать на каждую модель свой отдельный репозиторий.
Тут не стоит лениться - в дальнейшем будет меньше проблем.
Обычно репозиторий возвращает вам список моделей или конкретную модель, кеширует какие-либо локальные данные и возвращает эти данные из кеша и вот это вот все. Но в нем нет и не должно быть НИКАКОЙ другой логики (особенно бизнес-логики). Чем он тупее - тем лучше. Положили модель куда-то, отдали модель.
Теперь немного про слои.
Самые первые реализации Clean Arctitecture под Android делили слои репозиториев так:
1. Интерфейс репозитория мы помещаем на уровне domain.
2. Реализацию (класс, наследующий интерфейс репозитория) на уровне data.
3. UseCases / Interactors инжектит в конструктор именно интерфейс репозитория, а не реализацию! Это тоже очень важно. Реализацию подставит DI-фреймворк.
Сейчас же, когда проекты стали делить на features (фичи), а еще большие проекты на features в отдельных модулях, принцип разделения на слои остался прежним (в каждом модуле фичи своя структура domain - data - presentation).
Еще стоит отдельно упомянуть, что репозитории могут реализовывать разные DataSource (обычно инжектится в конструктор), например:
class UserRepositoryImpl @Inject constructor(private val source: DataSource): ...
Для чего это нужно?
Ну например, один заинжекченный репозиторий работает с локальным кешем данных, а другой всегда получает данные из сети. Интерфейс репозитория один и тот же, но за счет подстановки нужной реализации DataSource в конструктор поведение меняется.
При этом сохраняется исходный интерфейс, что всегда удобно во время тестирования или рефакторинга.
И такое на практике встречается частенько.
По большому счет это все основы, которые стоит четко для себя понимать при работе с репозиторием.
Главное следуем картинке ниже, чтобы Dependency Rule не нарушался и будет вам счастье.
Кстати, стоит ли отдельно рассказать про этот самый Dependency Rule?
Пишите в комменты.
Забавные новости про GitHub Copilot - AI-помощник программиста.
Первые пользователи поигрались и нашли ряд недостатков, но самое забавное в этом вот что: периодически Copilot вместо нескольких строк кода генерирует цитаты и комментарии из проектов с открытым исходным кодом. Кроме того, он вытаскивает валидные ключи API из репозиториев с открытым исходным кодом разных проектов и выдаёт их пользователям.
С одной стороны хранить открытые ключи - такое, с другой - норм так скрипт получился 🙂
Пока что выдыхаем и работаем дальше - мы все еще нужны.
Детали: https://habr.com/ru/news/t/576228/
Первые пользователи поигрались и нашли ряд недостатков, но самое забавное в этом вот что: периодически Copilot вместо нескольких строк кода генерирует цитаты и комментарии из проектов с открытым исходным кодом. Кроме того, он вытаскивает валидные ключи API из репозиториев с открытым исходным кодом разных проектов и выдаёт их пользователям.
С одной стороны хранить открытые ключи - такое, с другой - норм так скрипт получился 🙂
Пока что выдыхаем и работаем дальше - мы все еще нужны.
Детали: https://habr.com/ru/news/t/576228/
Хабр
Пользователи обнаружили 1170 слов, которые блокирует GitHub Copilot
Пользователи обнаружили в базе нейросетевого помощника программиста GitHub Copilot («второй пилот») 1170 стоп-слов, которые он блокирует при формировании кода. Среди них присутствуют такие...
Играемся с анимациями в Compose
Начал ковырять, как добавить простую анимацию для элементов.
Надо сказать, что вариантов сделать это довольно много.
Для простоты добавим анимацию исчезновения / появления температуры при свайпе (обновлении данных).
Добавить ее можно поместив анимируемый элемент (компонент) внутрь блока Composable-функции (в нашем случае AnimatedVisibility):
По-умолчанию анимация fadeIn() + expandIn() для enter и shrinkOut() + fadeOut() для exit, но в параметрах можно задать любые другие из списка в доке, а через оператор + их еще и можно миксовать, как вы уже догадались.
Пока этот API нужно помечать специальной аннотацией, как экспериментальный. Видимо API еще будет немного меняться, но не до конца понятно, как например, сделать свою длительность анимации (обычно есть какое-нибудь поле duration).
Что ж, будем ковырять дальше.
Ощущение, что возможностей море, но описано это все пока не очень подробно.
Дока: https://developer.android.com/jetpack/compose/animation
Больше примеров здесь: https://medium.com/wizeline-mobile/jetpack-compose-animations-i-f46024bcfa37
и здесь: https://proandroiddev.com/animate-with-jetpack-compose-animate-as-state-and-animation-specs-ffc708bb45f8
Начал ковырять, как добавить простую анимацию для элементов.
Надо сказать, что вариантов сделать это довольно много.
Для простоты добавим анимацию исчезновения / появления температуры при свайпе (обновлении данных).
Добавить ее можно поместив анимируемый элемент (компонент) внутрь блока Composable-функции (в нашем случае AnimatedVisibility):
AnimatedVisibility(
visible = !isRefreshing,
) {
Text(
text = temprature.toString(),
style = Typography.h3
)
}
Анимация в Compose завязана на состояния (как и все остальное, что логично), поэтому мы добавляем поле isRefreshing, которое меняется при swipe to refresh,По-умолчанию анимация fadeIn() + expandIn() для enter и shrinkOut() + fadeOut() для exit, но в параметрах можно задать любые другие из списка в доке, а через оператор + их еще и можно миксовать, как вы уже догадались.
Пока этот API нужно помечать специальной аннотацией, как экспериментальный. Видимо API еще будет немного меняться, но не до конца понятно, как например, сделать свою длительность анимации (обычно есть какое-нибудь поле duration).
Что ж, будем ковырять дальше.
Ощущение, что возможностей море, но описано это все пока не очень подробно.
Дока: https://developer.android.com/jetpack/compose/animation
Больше примеров здесь: https://medium.com/wizeline-mobile/jetpack-compose-animations-i-f46024bcfa37
и здесь: https://proandroiddev.com/animate-with-jetpack-compose-animate-as-state-and-animation-specs-ffc708bb45f8
Продолжаем понемногу копать анимации в Compose.
Один из вариантов, как можно установить длительность - это задать свою анимацию появления или исчезновения (параметры enter / exit).
Зададим, например, анимацию появления:
Вообще, в animationSpec может быть все что угодно, что реализует интерфейс AnimationSpec (неожиданно, да?) и скорее всего намиксовать в этом параметре опций можно много.
Такие дела.
Один из вариантов, как можно установить длительность - это задать свою анимацию появления или исчезновения (параметры enter / exit).
Зададим, например, анимацию появления:
AnimatedVisibility(
visible = !isRefreshing,
enter = fadeIn(animationSpec = tween(1000))
)
Длительность определяется функцией tween(). В нашем случае - 1 секунда.Вообще, в animationSpec может быть все что угодно, что реализует интерфейс AnimationSpec (неожиданно, да?) и скорее всего намиксовать в этом параметре опций можно много.
Такие дела.
Уже пару недель привыкаю / изучаю / назовите как угодно MVI архитектуру presеentation-слоя, которая ляжет на наш новый чудо-UI на базе Compose.
Лучшие статьи скину отдельным постом (посмотрел уже порядка двух десятков, в том числе и для iOS).
Толковых статей не так много, а многие другие обычно состоят из кальки документации по Redux с какими-то своими авторскими особенностями.
Ковыряя существующие решения, буквально вчера случайно увидел этот пост: https://appmattus.medium.com/top-android-mvi-libraries-in-2021-de1afe890f27
Автор сравнивает почти все уже существующие либы для MVI и возможно кому-то будет полезно, когда будете подбирать библиотеку себе.
Но в статье есть два нюанса:
1. В сравнении нет, наверное, самой популярной либы - либы от Badoo - MVICore.
2. Автор в начале утверждает, что свое решение для MVI делать сложно и не очень правильно. Но как по мне, стоит это принимать на веру не до конца, ведь исходя из общей концепции и той же самой доки по Redux - сложного в архитектуре не так много. На первых парах наоборот видится лучшим решением попробовать самостоятельно разобраться в основах и накидать примеры, добавив условно всего несколько интерфейсов, а потом уже перейти на нормальную библиотеку, если это вообще будет нужно. Основная проблема - правильное управление состоянием и разбухание этого самого состояния.
Но об этом позже.
Немного посмотрев на все эти либы, MVICore, Orbit-MVI пока выглядят наиболее адекватными из всех решений.
Есть еще MVIFlow, но она пока еще сыровата.
Поглядим.
Кстати, свои небольшие наброски по MVI сейчас делаю в отдельной ветке: https://github.com/Djangist/ComposeArchSample/tree/feature/udf_mvi
Заглядывайте, пишите под этим постом - пообщаемся.
А чуть позже еще появятся веточки для указанных выше двух либ - для сравнения.
Лучшие статьи скину отдельным постом (посмотрел уже порядка двух десятков, в том числе и для iOS).
Толковых статей не так много, а многие другие обычно состоят из кальки документации по Redux с какими-то своими авторскими особенностями.
Ковыряя существующие решения, буквально вчера случайно увидел этот пост: https://appmattus.medium.com/top-android-mvi-libraries-in-2021-de1afe890f27
Автор сравнивает почти все уже существующие либы для MVI и возможно кому-то будет полезно, когда будете подбирать библиотеку себе.
Но в статье есть два нюанса:
1. В сравнении нет, наверное, самой популярной либы - либы от Badoo - MVICore.
2. Автор в начале утверждает, что свое решение для MVI делать сложно и не очень правильно. Но как по мне, стоит это принимать на веру не до конца, ведь исходя из общей концепции и той же самой доки по Redux - сложного в архитектуре не так много. На первых парах наоборот видится лучшим решением попробовать самостоятельно разобраться в основах и накидать примеры, добавив условно всего несколько интерфейсов, а потом уже перейти на нормальную библиотеку, если это вообще будет нужно. Основная проблема - правильное управление состоянием и разбухание этого самого состояния.
Но об этом позже.
Немного посмотрев на все эти либы, MVICore, Orbit-MVI пока выглядят наиболее адекватными из всех решений.
Есть еще MVIFlow, но она пока еще сыровата.
Поглядим.
Кстати, свои небольшие наброски по MVI сейчас делаю в отдельной ветке: https://github.com/Djangist/ComposeArchSample/tree/feature/udf_mvi
Заглядывайте, пишите под этим постом - пообщаемся.
А чуть позже еще появятся веточки для указанных выше двух либ - для сравнения.
Medium
Top Android MVI libraries in 2021
Comparing redux and MVVM+ style MVI libraries
Либ для MVI / Unidirectional Data Flow становится все больше.
Вот, например, наши любимые ребята из Square, которые подарили нам множество прекрасных библиотек, выпустили свою: https://github.com/square/workflow/
Но прелесть ее в том, что она и для iOS и для Android, в отдельных зависимостях под каждую платформу. Кто-то захочет пойти в кроссплатформу и использовать обе, кто-то возьмет только версию под конкретную платформу. Такое разделение нравится.
Кроме того, либа не выглядит перегруженной своими абстракциями, хотя здесь они тоже чуть отличаются от принятых в том же Redux. Видится, что ее можно использовать как отдельно докрутив свои нужные слои (например, добавив свой Middleware), либо с другими либами.
Вообщем, выглядит любопытно.
Вот, например, наши любимые ребята из Square, которые подарили нам множество прекрасных библиотек, выпустили свою: https://github.com/square/workflow/
Но прелесть ее в том, что она и для iOS и для Android, в отдельных зависимостях под каждую платформу. Кто-то захочет пойти в кроссплатформу и использовать обе, кто-то возьмет только версию под конкретную платформу. Такое разделение нравится.
Кроме того, либа не выглядит перегруженной своими абстракциями, хотя здесь они тоже чуть отличаются от принятых в том же Redux. Видится, что ее можно использовать как отдельно докрутив свои нужные слои (например, добавив свой Middleware), либо с другими либами.
Вообщем, выглядит любопытно.
GitHub
GitHub - square/workflow: A Swift and Kotlin library for making composable state machines, and UIs driven by those state machines.
A Swift and Kotlin library for making composable state machines, and UIs driven by those state machines. - GitHub - square/workflow: A Swift and Kotlin library for making composable state machines,...