Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Реализация MVP с Moxy

Реализация MVP с Moxy

Avatar for Alidibir Akhbulatov

Alidibir Akhbulatov

January 23, 2019

More Decks by Alidibir Akhbulatov

Other Decks in Programming

Transcript

  1. Как библиотека работает? Что произошло здесь: 1. На View произошло

    действие , которое передается к Presenter'u 2. Presenter отправляет команду к ViewState
  2. Как библиотека работает? Что произошло здесь: 1. На View произошло

    действие , которое передается к Presenter'u 2. Presenter отправляет команду к ViewState
  3. Как библиотека работает? Что произошло здесь: 1. На View произошло

    действие , которое передается к Presenter'u 2. Presenter отправляет команду к ViewState 3. ViewState добавляет команду в очередь команд, и затем передает ее к View
  4. Как библиотека работает? 4. View приводит себя в состояние, заданное

    в команде 5. Presenter стартует асинхронный запрос к Model
  5. Как библиотека работает? 4. View приводит себя в состояние, заданное

    в команде 5. Presenter стартует асинхронный запрос к Model
  6. Как библиотека работает? 4. View приводит себя в состояние, заданное

    в команде 5. Presenter стартует асинхронный запрос к Model 6. Presenter принимает результат запроса от Model
  7. Как библиотека работает? 4. View приводит себя в состояние, заданное

    в команде 5. Presenter стартует асинхронный запрос к Model 6. Presenter принимает результат запроса от Model
  8. Как библиотека работает? 4. View приводит себя в состояние, заданное

    в команде 5. Presenter стартует асинхронный запрос к Model 6. Presenter принимает результат запроса от Model 7. Presenter отправляет команду к ViewState
  9. Как библиотека работает? 8. ViewState добавляет команду в очередь команд,

    удаляет сущ-ю команду и затем передает ее к View
  10. Как библиотека работает? 8. ViewState добавляет команду в очередь команд,

    удаляет сущ-ю команду и затем передает ее к View 9. View приводит себя в состояние, заданное в команде
  11. Как библиотека работает? 8. ViewState добавляет команду в очередь команд,

    удаляет сущ-ю команду и затем передает ее к View 9. View приводит себя в состояние, заданное в команде
  12. Как библиотека работает? 8. ViewState добавляет команду в очередь команд,

    удаляет сущ-ю команду и затем передает ее к View 9. View приводит себя в состояние, заданное в команде
  13. Как библиотека работает? 8. ViewState добавляет команду в очередь команд,

    удаляет сущ-ю команду и затем передает ее к View 10. Presenter отправляет команду к ViewState 9. View приводит себя в состояние, заданное в команде
  14. Как библиотека работает? 11. ViewState добавляет команду в очередь команд

    и затем передает ее к View 12. View приводит себя в состояние, заданное в команде
  15. Как библиотека работает? 11. ViewState добавляет команду в очередь команд

    и затем передает ее к View 12. View приводит себя в состояние, заданное в команде
  16. Как библиотека работает? 11. ViewState добавляет команду в очередь команд

    и затем передает ее к View 13. Воссозданый View прикрепляется к сущ-му Presenter'u 12. View приводит себя в состояние, заданное в команде
  17. Что мы хотим от Moxy? 1. Presenter должен существовать независимо

    от ЖЦ View 2. Воссозданный View должен использовать тот же экземпляр Presenter'a, который использовался до воссоздания
  18. Что мы хотим от Moxy? 1. Presenter должен существовать независимо

    от ЖЦ View 2. Воссозданный View должен использовать тот же экземпляр Presenter'a, который использовался до воссоздания 3. View должен показывать актуальное состояние UI-логики (Presenter'a) в каждый момент времени в не зависимости от момента прикрепления к Presenter'u
  19. Что мы хотим от Moxy? 1. Presenter должен существовать независимо

    от ЖЦ View 2. Воссозданный View должен использовать тот же экземпляр Presenter'a, который использовался до воссоздания 3. View должен показывать актуальное состояние UI-логики (Presenter'a) в каждый момент времени в не зависимости от момента прикрепления к Presenter'u 4. Никакого бойлерплейт-кода для этих целей
  20. Добавление базового модуля Moxy и модуля компилятора в зависимостях: dependencies

    { ... implementation 'com.arello-mobile:moxy:1.5.5' annotationProcessor 'com.arello-mobile:moxy-compiler:1.5.5' }
  21. Добавление базового модуля Moxy и модуля компилятора в зависимостях: dependencies

    { ... implementation 'com.arello-mobile:moxy:1.5.5' annotationProcessor 'com.arello-mobile:moxy-compiler:1.5.5' } Базовый модуль обеспечивает такие компоненты, как MvpPresenter, MvpView и т.д.
  22. Добавление базового модуля Moxy и модуля компилятора в зависимостях: dependencies

    { ... implementation 'com.arello-mobile:moxy:1.5.5' annotationProcessor 'com.arello-mobile:moxy-compiler:1.5.5' } Базовый модуль обеспечивает такие компоненты, как MvpPresenter, MvpView и т.д. Модуль компилятора генерирует код:
  23. Добавление базового модуля Moxy и модуля компилятора в зависимостях: dependencies

    { ... implementation 'com.arello-mobile:moxy:1.5.5' annotationProcessor 'com.arello-mobile:moxy-compiler:1.5.5' } Базовый модуль обеспечивает такие компоненты, как MvpPresenter, MvpView и т.д. Модуль компилятора генерирует код: - Для создания и инъекции MvpPresenter'a
  24. Добавление базового модуля Moxy и модуля компилятора в зависимостях: dependencies

    { ... implementation 'com.arello-mobile:moxy:1.5.5' annotationProcessor 'com.arello-mobile:moxy-compiler:1.5.5' } Базовый модуль обеспечивает такие компоненты, как MvpPresenter, MvpView и т.д. Модуль компилятора генерирует код: - Для создания и инъекции MvpPresenter'a - ViewState'a
  25. Добавление базового модуля Moxy и модуля компилятора в зависимостях: dependencies

    { ... implementation 'com.arello-mobile:moxy:1.5.5' annotationProcessor 'com.arello-mobile:moxy-compiler:1.5.5' } Базовый модуль обеспечивает такие компоненты, как MvpPresenter, MvpView и т.д. Модуль компилятора генерирует код: - Для создания и инъекции MvpPresenter'a - ViewState'a - Для инъекции ViewState'a к Presenter'u
  26. Для доп. классов MvpActivity и MvpFragment: Для AppCompat есть аналоги

    MvpAppCompatActivity и MvpAppCompatFragment: dependencies { ... implementation 'com.arello-mobile:moxy-android:1.5.5' }
  27. Для доп. классов MvpActivity и MvpFragment: Для AppCompat есть аналоги

    MvpAppCompatActivity и MvpAppCompatFragment: dependencies { ... implementation 'com.arello-mobile:moxy-android:1.5.5' } dependencies { ... implementation 'com.arello-mobile:moxy-app-compat:1.5.5' }
  28. Экран "Список юзеров" interface UsersView : MvpView { fun showUsers(users:

    List<User>) fun showLoadingProgress(show: Boolean) fun showLoadingError(message: String) }
  29. Экран "Список юзеров" interface UsersView : MvpView { fun showUsers(users:

    List<User>) fun showLoadingProgress(show: Boolean) fun showLoadingError(message: String) fun navigateToUserInfo(user: User) }
  30. Экран "Список юзеров" interface UsersView : MvpView { fun showUsers(users:

    List<User>) fun showLoadingProgress(show: Boolean) fun showLoadingError(message: String) fun navigateToUserInfo(user: User) } Интерфейс UsersView должен унаследоваться от MvpView
  31. Реализация интерфейса UsersView: class UsersFragment : MvpAppCompatFragment(), UsersView { override

    fun showUsers(users: List<User>) { // Отображает список юзеров } }
  32. Реализация интерфейса UsersView: class UsersFragment : MvpAppCompatFragment(), UsersView { override

    fun showUsers(users: List<User>) { // Отображает список юзеров } override fun showLoadingProgress(show: Boolean) { // Отображает прогресс на время загрузки списка юзеров } }
  33. Реализация интерфейса UsersView: class UsersFragment : MvpAppCompatFragment(), UsersView { override

    fun showUsers(users: List<User>) { // Отображает список юзеров } override fun showLoadingProgress(show: Boolean) { // Отображает прогресс на время загрузки списка юзеров } override fun showLoadingError(message: String) { // Отображает ошибку загрузки } }
  34. Реализация интерфейса UsersView: class UsersFragment : MvpAppCompatFragment(), UsersView { override

    fun showUsers(users: List<User>) { // Отображает список юзеров } override fun showLoadingProgress(show: Boolean) { // Отображает прогресс на время загрузки списка юзеров } override fun showLoadingError(message: String) { // Отображает ошибку загрузки } fun navigateToUserInfo(user: User) { // Выполняет переход на экран "Инфо о юзере" } }
  35. Реализация интерфейса UsersView: class UsersFragment : MvpAppCompatFragment(), UsersView { override

    fun showUsers(users: List<User>) { // Отображает список юзеров } override fun showLoadingProgress(show: Boolean) { // Отображает прогресс на время загрузки списка юзеров } override fun showLoadingError(message: String) { // Отображает ошибку загрузки } fun navigateToUserInfo(user: User) { // Выполняет переход на экран "Инфо о юзере" } } В случае Activity (UsersActivity) необходимо унаследоваться от MvpAppCompatActivity
  36. Реализация презентера UsersPresenter class UsersPresenter( private val dataManager: DataManager )

    : MvpPresenter<UsersView>() { override fun onFirstViewAttach() { super.onFirstViewAttach() loadUsers() } }
  37. Реализация презентера UsersPresenter class UsersPresenter( private val dataManager: DataManager )

    : MvpPresenter<UsersView>() { ... private fun loadUsers() { viewState.showLoadingProgress(true) } }
  38. Реализация презентера UsersPresenter class UsersPresenter( private val dataManager: DataManager )

    : MvpPresenter<UsersView>() { ... private fun loadUsers() { viewState.showLoadingProgress(true) dataManager.getUsers() .enqueue(object: Callback<List<User>?> { } } }
  39. Реализация презентера UsersPresenter class UsersPresenter( private val dataManager: DataManager )

    : MvpPresenter<UsersView>() { private fun loadUsers() { viewState.showLoadingProgress(true) dataManager.getUsers() .enqueue(object: Callback<List<User>?> { override fun onResponse( call: Call<List<User>?>, response: Response<List<User>?> ) { viewState.showLoadingProgress(false) if (response.isSuccessful) { viewState.showUsers(response.body()!!) } else { viewState .showLoadingError(response.message()) } } } } }
  40. Реализация презентера UsersPresenter class UsersPresenter( private val dataManager: DataManager )

    : MvpPresenter<UsersView>() { private fun loadUsers() { viewState.showLoadingProgress(true) dataManager.getUsers() .enqueue(object: Callback<List<User>?> { ... onResponse override fun onFailure( call: Call<List<User>?>, t: Throwable ) { if (!call.isCanceled) { viewState. showLoadingError(t.message!!) } } } } }
  41. Инъекция UsersPresenter во фрагмент/активность: class UsersFragment : MvpAppCompatFragment(), UsersView {

    .... @InjectPresenter lateinit var presenter: UsersPresenter @ProvidePresenter fun providePresenter(): UsersPresenter return UsersPresenter(App.dataManager) } }
  42. Доступные аннотации • @InjectPresenter • – аннотация для управления жизненным

    циклом Presenter • @InjectViewState • – аннотация для привязывания ViewState к Presenter
  43. Доступные аннотации • @InjectPresenter • – аннотация для управления жизненным

    циклом Presenter • @InjectViewState • – аннотация для привязывания ViewState к Presenter • @StateStrategyType
  44. Доступные аннотации • @InjectPresenter • – аннотация для управления жизненным

    циклом Presenter • @InjectViewState • – аннотация для привязывания ViewState к Presenter • @StateStrategyType • – аннотация для управления стратегией добавления и удаления команды из очереди команд во ViewState
  45. Инъекция презентера Moxy + Dagger 2 class UsersFragment : MvpAppCompatFragment(),

    UsersView { @InjectPresenter lateinit var presenter: UsersPresenter @ProvidePresenter fun providePresenter(): UsersPresenter return UsersPresenter() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ... } }
  46. Инъекция презентера Moxy + Dagger 2 class UsersFragment : MvpAppCompatFragment(),

    UsersView { @Inject @InjectPresenter lateinit var presenter: UsersPresenter @ProvidePresenter fun providePresenter(): UsersPresenter return presenter } override fun onCreate(savedInstanceState: Bundle?) { App.appComponent .plus(UsersModule()) .inject(this) super.onCreate(savedInstanceState) ... } }
  47. Частые ошибки You can not use @InjectPresenter in classes that

    are not View, which is typified target Presenter class UsersFragment : MvpAppCompatFragment() { .... }
  48. Частые ошибки You can not use @InjectPresenter in classes that

    are not View, which is typified target Presenter class UsersFragment : MvpAppCompatFragment(), UsersView { .... }
  49. java.lang.NullPointerException: Attempt to invoke interface method on a null object

    reference при обращении к полю viewState в презентере class UsersPresenter(private val dataManager: DataManager) : MvpPresenter<UsersView>() { override fun onFirstViewAttach() { super.onFirstViewAttach() loadUsers() } private fun loadUsers() { viewState.showLoadingProgress(true) .... } } Частые ошибки
  50. java.lang.NullPointerException: Attempt to invoke interface method on a null object

    reference при обращении к полю viewState в презентере @InjectViewState class UsersPresenter(private val dataManager: DataManager) : MvpPresenter<UsersView>() { override fun onFirstViewAttach() { super.onFirstViewAttach() loadUsers() } private fun loadUsers() { viewState.showLoadingProgress(true) .... } } Частые ошибки