Pull to refresh
17
0
Артур Артиков @a_artikov

Тимлид, Android-разработчик

Send message

Спасибо за статью.

Единственное, чего нам удалось добиться — это превращение App Links в обычные Web Links, которое влечет за собой появление диалога "устранения неоднозначности".

Можете, пожалуйста, раскрыть этот момент? Злоумышленник сможет сделать это, не имея доступа к нашему беку?

Привет. Крутая статья.

А как модификация байткода влияет на время сборки проекта?

Подписку на ChatGPT Plus можно получить и из России. Для этого нужны: впн, сервис для подтверждения смс (например, sms activate), виртуальная карта зарубежного банка (например, сервис pyypl).

Цена - 20$ в месяц. Но за то есть все функции: GPT 4 с ограничением 50 запросов в 3 часа, Advanced Data Analysis, генерация изображений через Dalle 3, распознавание содержимого на изображениях, поиск информации в интернете, сотни дополнительных плагинов.

Крутая статья. Очень жду продолжения)

Классная статья.

Подскажите, Кандинский поддерживает inpainting? Эта фича есть в Stable Diffusion. С ее помощью можно выделить часть изображения и сгенерировать заново. Очень полезно, чтоб исправлять проблемы с лицом, руками, оружием и т. д.

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

В отличие от StateFlow у Flow нельзя получить текущее значение. Это значит, что в collectAsState мы будем обязаны передать аргумент initial - в этом неудобство.

Про derivedStateOf просто проверьте, если не верите.

combine возвращает Flow. Утилита derived будет возвращать StateFlow, чтоб было удобнее.

Про derivedStateOf вы ошибаетесь. Она неявно подписывается на поля из лямбда-функции и потом автоматически пересчитывается при изменении любого из них.

Спасибо за дополнение.
Я не пробовал использовать упомянутые вами паттерны для реализации компонентного подхода. Будет интересно попробовать.

Выносить логику в UI, конечно, не стоит.

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

Если вы используете StateFlow, то нужно написать утилитную функцию (назовем ееderived) для комбинирования flow. С ней код получится таким:

    override val login = MutableStateFlow("")

    override val password = MutableStateFlow("")

    override val signInButtonEnabled = derived(login, password) { login, password ->
        login.isNotBlank() && password.isNotBlank()
    }

Или можно для состояния компонентов использовать State из Jetpack Compose и встроенную функцию derivedStateOf. Получится так:

    override val login by mutableStateOf("")

    override val password by mutableStateOf("")

    override val signInButtonEnabled by derivedStateOf {
        login.isNotBlank() && password.isNotBlank()
    }

Расскажите, пожалуйста, с какими неудобствами вы столкнулись, используя MVVM с Jetpack Compose?

Привет, Саша.

  1. Я сделал login, password и inProgress отдельными полями, потому что они могут изменяться независимо друг от друга. Если делать состояние компонента единым объектом, то это уже будет ближе к MVI, нежели к MVVM. Я не фанат MVI и редко его использую. Но, если тебе нравится MVI, то, конечно, его можно применять с компонентным подходом.

  2. В реальных приложениях я использую DI-фреймворк Koin. Для этого я создаю класс ComponentFactory — обертку поверх DI-контейнера с методами для создания компонентов. Сам ComponentFactory тоже зарегистрирован в DI, поэтому компоненты могут получить к нему доступ. Вот gist с примером.

Спасибо за интересные вопросы.

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

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

  1. Про получение данных в компонентах

    По возможности я стараюсь делать компоненты независимыми друг от друга. Для задачи "загрузить данные с сервера и отобразить их на экране" это всегда получается сделать.

    Предположим, что есть Компонент А и ему нужны какие-то данные с сервера. И есть Компонент Б, которому нужны те же самые данные.

    Можно сделать, чтоб Компонент А грузил данные, а Компонент Б как-то вытаскивал их из Компонента А. Но это плохое решение. Оно создает лишние зависимости между компонентами.

    Я предлагаю поступить по-другому. Пусть оба компонента обращаются за данными в репозиторий. Репозиторий нужно сделать достаточно умным — он должен выполнять дедупликацию запросов. Это значит, что если к нему обратиться за одними и теми же данными в течение небольшого промежутка времени, то сетевой запрос выполнится всего один раз.

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

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

  2. Про ЖЦ функциональных блоков

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

Нет, это значит, что компонентный подход был применен неправильно. Вы ударили себе молотком по пальцу и из этого сделали вывод "Молотки - это плохо".

Не надо так делать, и тогда будет счастье)

Суть компонентного подхода - разделить сложную штуку на более простые части. Это не может не работать.

А вот криво реализовать это в коде, конечно, можно. Тут с вами спорить не буду)

UFO landed and left these words here

Я имел ввиду, почему не делать, чтоб функция возвращала данные в случае успеха и кидала исключение при ошибке?

А почему бы не использовать исключения для ошибок?

Первый вариант именования цветов — использование названия цвета как есть: “realblue”, “darkgrey” и так далее.
Этот вариант рекомендует Google. Об этом упоминается в докладе и так сделано в примере Reply.
Но эти имена не надо напрямую использовать в лайаутах и стилях. Надо завести в теме атрибуты, имеющие уже семантические имена и ссылающиеся на цвета, и использовать их.

А ещё textAppearance можно описывать не все атрибуты — например, там нет свойства android:lineSpacingMultiplier.
Меня это тоже расстроило. Но потом оказалось, что в material-component поддерживается lineHeight (ссылка на код).

Позже этот процесс можно будет автоматизировать с помощью скриншотного тестирования.
Вопрос не по теме. В вашей компании есть опыт использования скриншотов для автоматизации тестирования?

В разделе "Проблема" ставится задача "Отобразить ленту с двумя типами данных — текст с описанием и картинка", а в разделе "Решение" решается другая задача.

1

Information

Rating
Does not participate
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Date of birth
Registered
Activity

Specialization

Mobile Application Developer
Lead
Android development