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

Поделиться
HTML-код
  • Опубликовано: 8 июн 2024
  • Показываю реальный пример на пальцах для "чайников" :) с применением паттерна MVI в Android. Все показываю на практике в коде и на диаграмме. Также разбираем MVI в архитектуре Clean Architecture (Чистая архитектура).
    MVI расшифровывается как: Model View Intent.
    Записаться ко мне на индивидуальные занятия или групповые курсы по Android можно на: ✅ KIPARO.COM.
    СОДЕРЖАНИЕ:
    -------------------------------------------------------------------
    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 - подводим итоги
    -------------------------------------------------------------------
    На канале также есть и другие уроки по программированию.
    Так же, найти меня можно вот тут:
    ✅ Linkedin: / timofeykovalenko
    ✅ Instagram: / ttimofey
    ✅ На моем сайте: kiparo.com/teacher/timofey-ko...
    #mvi #android #kiparo

Комментарии • 85

  • @TimofeyKovalenko
    @TimofeyKovalenko  Год назад +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 - подводим итоги

  • @user-dt4jh4jd5z
    @user-dt4jh4jd5z Год назад +11

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

  • @stasleonov5196
    @stasleonov5196 Год назад +17

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад

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

    • @stasleonov5196
      @stasleonov5196 Год назад +5

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

    • @spam397
      @spam397 Год назад

      Поддержу.

  • @olegleonov1310
    @olegleonov1310 Год назад +18

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад +3

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

    • @user-zi8zw3yf2t
      @user-zi8zw3yf2t Год назад

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

    • @DortanMors
      @DortanMors Год назад

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

    • @user-xg3no4yh4q
      @user-xg3no4yh4q Месяц назад

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

  • @relax7299
    @relax7299 Год назад +4

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

  • @user-uj4qx2wi8n
    @user-uj4qx2wi8n Год назад +1

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

  • @jahongirzokirov3453
    @jahongirzokirov3453 Год назад

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

  • @alexandralban5682
    @alexandralban5682 Год назад

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

  • @user-vm9kh7je4p
    @user-vm9kh7je4p Год назад

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

  • @alextroy605
    @alextroy605 11 месяцев назад +1

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

  • @azatsabirov863
    @azatsabirov863 Год назад

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

  • @la5926
    @la5926 Год назад +4

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад +6

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

  • @nomugop8017
    @nomugop8017 Год назад

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

  • @ArtemSamoshkin
    @ArtemSamoshkin 5 месяцев назад

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

  • @user-jc7nu3tw4h
    @user-jc7nu3tw4h Год назад

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

  • @roman_je_rkoff
    @roman_je_rkoff Год назад +3

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

  • @user-tg1yr1dt4n
    @user-tg1yr1dt4n Год назад

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

  • @misterex99
    @misterex99 Год назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад

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

  • @rainbowman8602
    @rainbowman8602 Год назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад

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

  • @buddaset4226
    @buddaset4226 Год назад

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

  • @Revakovskyi
    @Revakovskyi Год назад

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

  • @Klimpton
    @Klimpton 11 месяцев назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  10 месяцев назад

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

    • @user-xg3no4yh4q
      @user-xg3no4yh4q Месяц назад

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

  • @DaniilK-hq5go
    @DaniilK-hq5go Год назад

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

  • @maksym1266
    @maksym1266 6 месяцев назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  6 месяцев назад

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

  • @igornovikov6337
    @igornovikov6337 Год назад

    🔥🔥🔥🔥🔥🔥

  • @eugenebutov4364
    @eugenebutov4364 Год назад +1

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад

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

    • @user-zi8zw3yf2t
      @user-zi8zw3yf2t Год назад

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

  • @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)

  • @Mecenatt
    @Mecenatt Год назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  11 месяцев назад

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

  • @user-qh4wx5wb7p
    @user-qh4wx5wb7p Год назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад

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

    • @user-qh4wx5wb7p
      @user-qh4wx5wb7p Год назад

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

  • @vsv8161
    @vsv8161 Год назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад

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

  • @ulmaxy
    @ulmaxy Год назад +1

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад +3

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

    • @ulmaxy
      @ulmaxy Год назад

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

  • @karamba6936
    @karamba6936 Год назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад

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

  • @voicetv9048
    @voicetv9048 8 месяцев назад +1

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  8 месяцев назад

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

  • @user-zh5il3gg6v
    @user-zh5il3gg6v Год назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад

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

    • @user-xg3no4yh4q
      @user-xg3no4yh4q Месяц назад

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

  • @WarmHug451
    @WarmHug451 Год назад

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

  • @stilipgame421
    @stilipgame421 Год назад +1

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад +1

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

  • @inquisitor4894
    @inquisitor4894 6 месяцев назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  6 месяцев назад

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

    • @inquisitor4894
      @inquisitor4894 6 месяцев назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  6 месяцев назад

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

  • @romankryvolapov7961
    @romankryvolapov7961 Год назад +1

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

  • @frednekrasov7019
    @frednekrasov7019 5 месяцев назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  4 месяца назад

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

  • @olegevdoshenko1675
    @olegevdoshenko1675 Год назад +1

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

    • @readmeandanswer8142
      @readmeandanswer8142 Год назад +2

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

    • @user-xg3no4yh4q
      @user-xg3no4yh4q Месяц назад

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

  • @VoroninSergey
    @VoroninSergey Год назад +2

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад

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

    • @VoroninSergey
      @VoroninSergey Год назад +1

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

    • @user-xg3no4yh4q
      @user-xg3no4yh4q Месяц назад

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

    • @VoroninSergey
      @VoroninSergey Месяц назад

      @@user-xg3no4yh4q Интерфейсы тоже есть

  • @kamanchomorgan9655
    @kamanchomorgan9655 6 месяцев назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  4 месяца назад

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

  • @user-zi8zw3yf2t
    @user-zi8zw3yf2t Год назад

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

    • @TimofeyKovalenko
      @TimofeyKovalenko  Год назад +1

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

    • @user-zi8zw3yf2t
      @user-zi8zw3yf2t Год назад

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