MVI в Android на практике

แชร์
ฝัง
  • เผยแพร่เมื่อ 17 พ.ย. 2024

ความคิดเห็น • 88

  • @TimofeyKovalenko
    @TimofeyKovalenko  2 ปีที่แล้ว +6

    СОДЕРЖАНИЕ:
    00:00:00 - введение
    00:01:34 - Архитектура MVVM с Clean Architecture, как основа для MVI
    00:02:56 - MVI на диаграмме
    00:05:09 - Model-View-Intent на практике в коде
    00:05:42 - Меняем ViewModel по архитектуре MVI
    00:08:56 - Адаптирем Android Activity под MVI
    00:09:25 - Реализуем State в MVI
    00:16:14 - Запускаем Android приложение
    00:17:32 - подводим итоги

  • @АлександрХодосок-ь2м
    @АлександрХодосок-ь2м ปีที่แล้ว +11

    Ещё не добрался до MVI, но пишу комментарий здесь чтобы возможно ты увидел его. Огромное спасибо за твою подачу столь сложных вещей, я уверен что благодаря тебе очень много джуниоров прошли свои собеседования и работают во благо мобильной разработки! Для тех, кто недавно влился в мобилку скажу. Я посмотрел видео про MVVM месяца так два назад, и честно сказать просто переписал код, но не понял как и куда его использовать, пересмотрел видео сегодня, всё понял и всё впитал. Я это к чему, не парьтесь, что не понимаете вещей прямо сейчас, через время вам эти вещи будут казаться просто пустяками легчайшими, набивайте руку и делайте свои проекты(вначале говнокодьте, куда ж без этого). Спасибо Тимофею за его видосы, смотрю теорию в метро, решаю практику дома

  • @stasleonov5196
    @stasleonov5196 2 ปีที่แล้ว +17

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 ปีที่แล้ว

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

    • @stasleonov5196
      @stasleonov5196 2 ปีที่แล้ว +6

      @@TimofeyKovalenko буду ждать, у вас талант от бога объяснять сложные вещи.

    • @spam397
      @spam397 2 ปีที่แล้ว +1

      Поддержу.

  • @olegleonov1310
    @olegleonov1310 2 ปีที่แล้ว +18

    Как идея заменить interface MainEvent на sealed class MainEvent. Чтобы не смогли передать state, который не описан в MainViewModel. Так мы защитим свой от наследования от MainEvent уже после того как у нас будет написан код, чтобы не оказалось, что кто-то сможет передать необрабатываемое состояние. Плюс при использовании sealed сlass компилятор автоматиченски проверит все when и не даст собрать, если мы забудем обработать какое-то состояние или другой разработчик добавит новое состояние и не добавит обработку.
    Но можно и не делать, конечно)

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 ปีที่แล้ว +4

      Да, это хороший вариант, я бы так и рекомендовал делать.

    • @ДенисСаранин-м1и
      @ДенисСаранин-м1и 2 ปีที่แล้ว

      А файл не разбухнет описать все ивенты в одном классе?

    • @DortanMors
      @DortanMors 2 ปีที่แล้ว

      @@ДенисСаранин-м1и можно и не в одном файле. Sealed можно раскидать в рамках одного пакета в модуле.

    • @РоманМатохин
      @РоманМатохин 7 หลายเดือนก่อน

      при просмотре видео тоже подумал о sealed class)))

  • @relax7299
    @relax7299 2 ปีที่แล้ว +4

    Ура! Уроки вернулись, спасибо большое!

  • @ArtemSamoshkin
    @ArtemSamoshkin 10 หลายเดือนก่อน

    Самое понятное описание паттерна MVI. Благодарю!

  • @Тамнормально
    @Тамнормально 2 ปีที่แล้ว +1

    Огромное спасибо! Пытался уже читать статьи по MVI и даже намека на понимание не было. А тут всё очень доступно объяснено.

  • @alextroy605
    @alextroy605 ปีที่แล้ว +1

    Отличное объяснение, впервые хоть немного понял mvi. На работе редьбкс, там ещё хуже 😂

  • @jahongirzokirov3453
    @jahongirzokirov3453 2 ปีที่แล้ว

    сразу лайк, Тимофей!) По твоим видео учил как архитектуру строить!)

  • @СергейГорюнов-ы4ч
    @СергейГорюнов-ы4ч 2 ปีที่แล้ว

    Кратко и доступно) Большое спасибо за урок!

  • @PavelStr-x5w
    @PavelStr-x5w 4 หลายเดือนก่อน

    Большое спасибо за урок !!!

  • @nomugop8017
    @nomugop8017 2 ปีที่แล้ว

    Пока что лучшее, из того, что нашел ) спасибо. Без воды коротко и ясно.
    Думаю стоило использовать enum или sealed, но подозреваю, что это было сделано для простоты понимания. Еще раз спасибо.

  • @azatsabirov863
    @azatsabirov863 2 ปีที่แล้ว

    Спасибо! Как раз хотел понять суть MVI!

  • @Николайучёв
    @Николайучёв 2 ปีที่แล้ว

    Спасибо большое 😍
    Недавно вас нашёл, очень понравилось про MVVM, но огорчился, что уже пол года не выпускали ролики (

  • @alexandralban5682
    @alexandralban5682 2 ปีที่แล้ว

    Спасибо за урок! Все как обычно, ясно и понятно

  • @la5926
    @la5926 2 ปีที่แล้ว +4

    Это не MVI. MVI подразумевает, что у нас есть Reducer, который на вход принимает текущее состояние и изменения состояния, а на выходе отдает новое состояние целиком. Этот подход актуален больше для Jetpack Compose, потому что при такой ситуации он с помощью подкапотным diff на вьюшки будет переотрисовывать только изменения, но с xml вьюшками будет переотрисовываться все целеком и придется реализовывать свои diff.
    Пример реализации MVI - MVIKotlin, MVI Core Badoo.

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 ปีที่แล้ว +6

      У нас в примере Reducer это просто функция. Отсутствие названия Reducer не показатель того, что это не MVI:). А MVIKotlin, MVI Core Badoo - это уже специфичные реализации MVI подхода с кучей всего.

  • @Arman_127
    @Arman_127 2 ปีที่แล้ว

    Огромное вам спасибо, если бы все так учили =)

  • @misterex99
    @misterex99 ปีที่แล้ว

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว

      Про такое точно не будет видео, не специалист в этом вопросе.

  • @eugenebutov4364
    @eugenebutov4364 2 ปีที่แล้ว +1

    Вопросы такие:
    - чем плохо 2 публичных функции типа load / save ? чем этот подход плох в MVI ? Ведь если как и раньше к ним обращаться, то мы избавляемся от Event моделей.
    - как быть c singleEvents (сделай переход, покажи тоаст, показать диалог) которые нужно показать один раз. (где то у гугла читал, что они предлагают это добавить в стэйт, с той разницей что после прочтения этого события, его переводить в null или какой то нетральный стэй, который не будет вызывать повторное событие, при повторной подписке)

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 ปีที่แล้ว

      2 публичных метода не плохо, мне лично MVVM больше нравится и вполне устраивает. Тут просто другой подход, предлагающий единый обработчик для всего, что происходит в приложении. И да, с MVI много кода выходит, особенно, если событий прилично.
      C singleEvents все записываем в state и потом кидаем событие, что-бы обнулить это значение 🙂
      То есть на каждое действие создаем событие.

    • @ДенисСаранин-м1и
      @ДенисСаранин-м1и 2 ปีที่แล้ว

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

  • @ulmaxy
    @ulmaxy 2 ปีที่แล้ว +1

    Утверждение о том, что MVI это как MVVM, только со стейтами/экшенами не очень корректное. MVI не обязательно подразумевает использование того же механизма что и в MVVM для общения с View. MVI можно реализовать в связке с MVVM, а можно в связке с MVP, ибо MVVM/MVP отвечают за механизм взаимодействия вьюшки с логикой, а MVI позволяет определить как выглядят данные, которыми они обмениваются.
    В случае с MVP вы можете определить метод render(state: State) во View, и метод onAction(action: Action) в презентере, и это будет вполне себе MVI

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 ปีที่แล้ว +3

      Да, все верно, основу не обязательно брать в виде MVVM. Но в Android это наиболее популярный вариант, так как VM идет из коробки. MVP все же устаревшее решение, без официальной поддержки.

    • @ulmaxy
      @ulmaxy 2 ปีที่แล้ว

      @@TimofeyKovalenko согласен, сегодня трудно встретить mvp в новых проектах. Мой комментарий скорее про то, что применение MVI не обязательно связано строго с MVVM

  • @СергейБеляков-д5в
    @СергейБеляков-д5в ปีที่แล้ว

    Не плохо, разобрался поболее что и как. Единственное - MainEvent и его наследников мне кажется лучше выполнять в качестве sealed class

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว

      Да, все верно, в видео не хотелось усложнять.

    • @РоманМатохин
      @РоманМатохин 7 หลายเดือนก่อน

      @@TimofeyKovalenko это скорее не усложнение, а правильная практика)

  • @Mecenatt
    @Mecenatt ปีที่แล้ว

    Все понятно , круто , спасиб . Непонятно только то , что в mvvi для всего были свои "модельки" , чуть-ли не модельки для моделек. А в этом примере везде тупо STRING . Или это только для примера ?

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว

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

  • @Revakovskyi
    @Revakovskyi 2 ปีที่แล้ว

    Тимофей, спасибо Вам огромное за вашу проделанную работу! Благодаря вашим видео много понял и открыл для себя!
    Хочу вас попросить, если у вас будет желание, сделать материал по тому, как правильно маппить модели из разных слоев, а также модели, полученные через ретрофит и локальные базы данных.
    Спасибо вам!

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว +1

      Обязательно сделаю такое!

  • @voicetv9048
    @voicetv9048 ปีที่แล้ว +1

    Думаю лучше ли использовать sealed class в месте интерфейса чтобы видеть все возможные варианты а не запомнить каждый класс ✅

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว

      Конечно лучше). В видео просто упрощено, что-бы не вводить лишнее

  • @vdrmkr
    @vdrmkr ปีที่แล้ว

    а почему не sealed для Event`ов?

  • @maksym1266
    @maksym1266 ปีที่แล้ว

    Спасибо за видео. Как должен выглядить стейт, когда нужно так же хранить данные которые получены с domain?

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว

      Просто храните их внутри стейта в той же модельке, которую получили из domain. Либо можно создать UI модель, если там требуется дополнительная логика для отображения полученных даных.

  • @inquisitor4894
    @inquisitor4894 ปีที่แล้ว

    sealed class конечно по интереснее смотрится чем interface и просто class ниже в файле.
    так же хотелось услышать про .copy при изменении состояния + почему value, а не postValue

    • @TimofeyKovalenko
      @TimofeyKovalenko  11 หลายเดือนก่อน

      Про copy просто не стал усложнять. А зачем вам postValue тут? Не никакого смысла в нем.

    • @inquisitor4894
      @inquisitor4894 11 หลายเดือนก่อน

      Чтобы не нагружать дополнительно поток в котором происходит отрисовка экрана. Запустить туже корутину и там прописать postValue@@TimofeyKovalenko

    • @TimofeyKovalenko
      @TimofeyKovalenko  11 หลายเดือนก่อน

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

  • @Klimpton
    @Klimpton ปีที่แล้ว

    Привет, спасибо огромное за уроки, хотел спросить: В стейт мы получается должны записать все необходимые переменные, а допустим их будет 10-15, в каждой определенной функции типа save или load надо будет вручную присваивать нужные значения и сохранять старые ?

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว

      Да, но можно сделать функцию copy, что-бы не делать это каждый раз. Так же, есть смысл разбить UI на более мелкие со своими VM.

    • @РоманМатохин
      @РоманМатохин 7 หลายเดือนก่อน

      у data class есть метод copy(), который замечательно позволяет копировать старые значения не указывая их значения в параметрах, а только заменять значения у нужных, используя именованные параметры

  • @buddaset4226
    @buddaset4226 2 ปีที่แล้ว

    Как обрабатывать side эффекты в MVI?

  • @rainbowman8602
    @rainbowman8602 ปีที่แล้ว

    Здравствуйте, Тимофей! У меня такой вопрос, немного уточняющий. Если мы хотим иметь какую-то обработку ошибок, то в state нужно хранить условный screenState, который из себя представляет Sealed Class с различными стейтами экрана (загрузки, ошибки, дата и т.д.), верно?

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว

      Не обязательно, это может быть простая модель

  • @vsv8161
    @vsv8161 ปีที่แล้ว

    Здравствуйте, Тимофей
    Возможно ли ещё записаться к Вам на курсы?

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว

      Да, посмотри на главной странице вверху есть ссылка на набор в группу.

  • @олесясеулова
    @олесясеулова 4 หลายเดือนก่อน

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 หลายเดือนก่อน

      Да, поэтому нужно менять только те части, данные для которых изменились. С композ это все легко решается.

  • @АлексБор-б8я
    @АлексБор-б8я ปีที่แล้ว

    Тимофей, скажите пожалуйста, когда у вас будет старт набора на обучающий курс?

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว

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

    • @АлексБор-б8я
      @АлексБор-б8я ปีที่แล้ว

      @@TimofeyKovalenko это дружеские беседы в скайпе на общие интересующие темы, какой бизнес, какой налог? Обсудить детали «донатов» за ваш труд и вперёд!! Мы ждём!! :)

  • @frednekrasov7019
    @frednekrasov7019 10 หลายเดือนก่อน

    Спасибо, теперь-то я понял, в чем их разница. А почему так тихо?

    • @TimofeyKovalenko
      @TimofeyKovalenko  10 หลายเดือนก่อน

      С микрофоном бывает не угадаешь, а переснимать потом лень ;)

  • @VoroninSergey
    @VoroninSergey 2 ปีที่แล้ว +2

    Вместо простых интерфейсов лучше использовать sealed interfaces - так надёжней, если забыл написать обработчик - компилятор подскажет. И очень плохо каждый раз создавать новый стейт - легко потерять данные. Лучше создать дефолтный стейт, а при изменении использовать метод copy, это же data class

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 ปีที่แล้ว

      Простые интерфейсы используются что-бы понимание тоже простым было ;), тоже и с copyWith(). А так конечно же, это лучше.

    • @VoroninSergey
      @VoroninSergey 2 ปีที่แล้ว +1

      @@TimofeyKovalenko Это скорее необходимо. Лучше потратить пару минут на объяснение sealed interface и data class - без них в MVI лучше не суваться

    • @РоманМатохин
      @РоманМатохин 7 หลายเดือนก่อน +1

      @@VoroninSergey подушню немного - всё-таки код котлина, а в котлине нет sealed interface, там sealed class))

    • @VoroninSergey
      @VoroninSergey 7 หลายเดือนก่อน

      @@РоманМатохин Интерфейсы тоже есть

  • @stilipgame421
    @stilipgame421 ปีที่แล้ว +1

    Не легче было создавать новую версию MainState через copy? прописывая только изменившиеся свойства) не зря же data class используется

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว +1

      Да, но не хотелось усложнять еще какими-то конструкциями.

  • @WarmHug451
    @WarmHug451 2 ปีที่แล้ว

    Those explanations seems really nice, I wish I understood russian :/

  • @mikeshilovski1512
    @mikeshilovski1512 ปีที่แล้ว

    Я не так давно перечитывал developer документации и там был такой пример, что мы во view model создаём модель для хранения view state и все events обарачиваются в callback поля:
    val primaryActionClick: () -> Unit
    У меня вопрос немного не по теме, но я хочу узнать как нам в таком случае мапить модели которые мы получаем с backend в screen state model? К примеру, если на нужно доставать string resources через контекст (мы жже не можем делать это во view model)

    • @evgeniivorobei69
      @evgeniivorobei69 ปีที่แล้ว

      создай interface ResourcesInteractor, который дублирует методы для получения ресурсов. Создай его реализацию ResourcesInteractorImpl, которая и выдает ресурсы. Передай ResourcesInteractor туда, куда надо, через DI (dagger/koin)

  • @karamba6936
    @karamba6936 ปีที่แล้ว

    а этот подход случайно не под state flow сделан?Недавно смотрел видео про него

    • @TimofeyKovalenko
      @TimofeyKovalenko  ปีที่แล้ว

      Нет, но они хорошо сочетаются.

  • @romankryvolapov
    @romankryvolapov ปีที่แล้ว +1

    Думаю здесь нужны sealed классы

  • @igornovikov6337
    @igornovikov6337 2 ปีที่แล้ว

    🔥🔥🔥🔥🔥🔥

  • @olegevdoshenko1675
    @olegevdoshenko1675 2 ปีที่แล้ว +1

    Хотелось бы больше информации про навигацию между фрагментами с помощью cicerone, на просторах интернета очень мало на эту тематику, да и на самом деле, хотелось бы лично от вас услышать. Прошел первые 7 уроков из плейлиста по чистой архитектуре. Это невероятно, хоть и достаточно сложно к пониманию, но видео содержат 100% полезности)

    • @readmeandanswer8142
      @readmeandanswer8142 2 ปีที่แล้ว +2

      Почему мало? если на habr есть целая статья об этом? К тому же в README тоже понятно написано.

    • @РоманМатохин
      @РоманМатохин 7 หลายเดือนก่อน

      cicerone прошлый век, юзайте Android Navigation Component

  • @roman_je_rkoff
    @roman_je_rkoff ปีที่แล้ว +3

    у data class есть метод copy(), в который можно передать только изменяемые параметры, намного красивее будет чем каждый раз перезаписывать все поля. В видео нет приписки для чайников, поэтому можно было и это вставить)

  • @kamanchomorgan9655
    @kamanchomorgan9655 11 หลายเดือนก่อน

    Приватные методы во вьюмодели нетестируемы

    • @TimofeyKovalenko
      @TimofeyKovalenko  10 หลายเดือนก่อน

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

  • @ДенисСаранин-м1и
    @ДенисСаранин-м1и 2 ปีที่แล้ว

    Лайвдата? Мы вроде не на джабе пишем

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 ปีที่แล้ว +1

      А LiveData только на джаве может использоваться?). Используем самый простой инструмент для демонстрации. Если вы про корутины, то это отдельная тема.

    • @ДенисСаранин-м1и
      @ДенисСаранин-м1и 2 ปีที่แล้ว

      @@TimofeyKovalenko зачем лишняя библиотека