Как стать автором
Обновить

Комментарии 20

А не лучше ли будет использовать debounce вместо delay? С debounce отбросятся ненужные события и сразу будет нарисован нужный (последний) вариант. Это уменьшит общее количество отрисовок.

Более того, debounce можно повесить на события с UI на ViewModel, которые сообщают о смене позиции камеры, что уберёт часть запросов на сервер.

P.S. Compose рассматривает List (а они основа вашего MapUiState), как Unstable. Это приводит к лишним рекомпозициям, так как Compose не может понять, изменилось ли что-то в списке или нет и принудительно рекомпозирует. Попробуйте использовать неизменяемые коллекции.

debounce вместо delay я как раз не могу использовать, т.к. в очереди стоят разные MapUiState с данными по велосипедам, парковкам, станциям, медленным зонам, арендам и т.д. С debounce я потеряю всё :)

Вешать debounce на события с UI на ViewModel мне тоже не нужно, т.к. в Yandex Map SDK CameraListener уже имеет параметр “finished” и событие посылаются на ViewModel не на каждое движение пальца пользователя, а когда он немного притормаживает “неистовый” скролинг.

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

Большое спасибо за неизменяемые коллекции, проапдейтился на них.

В чем проблема несколько flow с данными разных типов собрать через combine в одну модель для UI? Передавать данные во вью для отрисовки кусками разных типов - оно в целом не очень как то идее декларативного UI фреймворка соответствует.

Ну и да, для событий перемещения как выше написали debounce неплохо иметь.

Для обновления UI я запрашиваю с сервера разные данные (велосипеды, парковки, станции, медленные зоны). Кроме этого раз в 10 сек. я запрашиваю данные об аренде. Все ответы приходят в разное время (а иногда приходит timeout exception). Если ждать получения всех данных и объединять их, пользователь может увидеть обновление экрана через n секунд, что недопустимо.

Про debounce выше ответил.

И это ничего не меняет. Не надо ждать получения всех данных. Никто не мешает по умолчанию пока реальные данные не пришли пустые отправлять, или из кэша какого нибудь. А после перемещения камеры - ранее полученные для другого положения (если надо отсеченные, без лишних), либо опять же пустые.

Решение на основе задержек - очень нестабильное и без гарантий для устройства. Сегодня она быстрая, а завтра там пользователь еще что запустит в фоне и все, уже 50 мс не хватит. Из-за таких задержек флагманы не могут показать своих преимуществ и потом говорят что устрйоства плохие, а не приложения

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

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

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

Вам там и объяснили, что если вы не хотели отрисовывать все вместе, вы должны были сделать по-другому и сделать семью вложенных состояний, как я объясняю в этой статье https://proandroiddev.com/how-to-safely-update-state-in-your-kotlin-apps-bf51ccebe2ef

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

Ну статью я удалять не буду, потому что тогда и реклама Вашей статьи пропадет ;)

А если серьезно, то статью я прочитал, но так и не понял как совершенно разные по смыслу и бизнес логике события типа данные об аренде, поступающие каждые 10+n секунд и данные об объектах на карте, поступающие в з-ти от действий пользователя объединить в "семью вложенных состояний"? Если приведете конкретный пример как это сделать, буду очень признателен.

Так это не MVI, это MVVM) Где тут Actor, Producer, Reducer? Я не люблю этот подход как раз из-за лишней сложности, и использую похожий на твой подход. У нас его называют "MVVM со стейтами". Можешь тоже так написать, чтобы нести идею в массы.

Насчёт debounce правильно подсказали, но есть ещё более крутой метод, который, судя по доке, считается не очень стабильным, но, на моей практике, он отлично работает. Это sample. Метод не имеет лишней задержки перед каждым отправлением события. Он как бы сохраняет последнее значение и возвращает его, когда внутренний duration удовлетворён. https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/sample.html

Ещё требуется понимать, что время от отправки событий через flow до получения слушателем - не мгновенно, а примерно 50мс. Поэтому отправлять события чаще чем эти 50мс попросту нельзя: даже умный диспетчер не переварит такую нагрузку, из-за чего вызовет подвисание UI.

И да, дважды подумай, нужно ли использовать delay внутри лямбды: лучше использовать расширения.

Спасибо за "MVVM со стейтами" внёс уточнение. Про debounce ответил выше.

Про delay внутри лямбды и расширения не очень понял, вроде как это стандартное решение.

Соответственно могу использовать современные frameworks и стараться сделать все по феншую

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

Интересно на сколько современные и на сколько по феншую просто.

Отрисовки по слоям в Yandex Map SDK для Android я не нашел. Про современные решения я имел в виду архитектуру Android приложения

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

Я с яндекс картами не работал особо, но там же классический артефакт View классов.

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

Возможно там стоит использовать лаунчэффекты или прямую подписку на Flow

И да хорошая идея другого комментатора про UnStable классы, можно сделать аннотацию Stable для ваших данных

Хм.. “лаунчэффекты или прямую подписку на Flow” не пробовал, но вроде и без этого все неплохо работает.. С UnStable идея действительно хорошая, но решил использовать “неизменяемые коллекции”, а не аннотацию Stable, т.к. дока рекомендует: “If it is possible to make your class stable without an annotation, you should strive to achieve stability that way.”

Хотелось бы увидеть, как у вас UI реализован. А то в статье про компоуз, но ни одной Composable-функции нет)

Ну почему одна есть:

val mapUiState by mapViewModel.mapUiState.collectAsStateWithLifecycle() :)

А если серьезно, то работа с Yandex Map SDK для Android достаточно специфична и это не совсем компоуз. Рассказать хотел именно про взаимодействие с ним.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории