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

Упрощаем рутину (списки 2.0)

GDG SPb
November 22, 2017

Упрощаем рутину (списки 2.0)

Мы рассмотрим самую часто встречающуюся задачу: экран со списком, для которого требуется реализовать ptr и пагинацию и последовательно разберем:
- типичный сценарий решения
- новые требования и к чему это ведёт: дублирование и запутанность кода
- составляем карту состояний и переходов
- наглядно о том, что простой для заказчика экран, на самом деле очень непростой
- пишем стейт машину, которую легко переносить из проекта в проект

GDG SPb

November 22, 2017
Tweet

More Decks by GDG SPb

Other Decks in Programming

Transcript

  1. Константин Цховребов Android Team Leader RedMadRobot • более 6 лет

    в отрасли • есть OpenSource проекты • DevFest, Mobius, AppsConf • архитектурная тусовка
  2. Акт первый. Экран какого-то списка. Загружает что-то с сервера и

    показывает список пользователю в самом простом виде.
  3. Акт первый. Правки. Экран какого-то списка. Загружает что-то с сервера

    и показывает список пользователю в самом простом виде. Ах да, можно обновить через PullToRefresh.
  4. Акт второй. Правки. Экран какого-то списка. … При пустых данных

    надо отобразить картинку с кнопкой. И при ошибке тоже.
  5. Акт второй. Правки. Экран какого-то списка. … При пустых данных

    надо отобразить картинку с кнопкой. И при ошибке тоже. Но не после обновления. (там просто тост)
  6. Акт третий. Правки. Экран какого-то списка. … Ошибка при пагинации?

    Toast и надо повторить при повторном скролле. (проверка на номер страницы) Пустые данные при пагинации? Больше не грузим страницы. (флаг о конце данных, который скидываем при обновлении) PullToRefresh при загрузке новой страницы? Отменяем пагинацию и обновляем все. (проверка на номер страницы) и так далее.
  7. private interface State<T> { fun refresh() {} fun loadNewPage() {}

    fun release() {} fun newData(data: List<T>) {} fun fail(error: Throwable) {} }
  8. interface ViewController<T> { fun showEmptyProgress(show: Boolean) fun showEmptyError(show: Boolean, error:

    Throwable? = null) fun showEmptyView(show: Boolean) fun showData(show: Boolean, data: List<T> = emptyList()) fun showErrorMessage(error: Throwable) fun showRefreshProgress(show: Boolean) fun showPageProgress(show: Boolean) }
  9. class Paginator<T>( private val requestFactory: (Int) -> Single<List<T>>, private val

    viewController: ViewController<T> ) { private val FIRST_PAGE = 1 private var currentState: State<T> = EMPTY() private var currentPage = 0 private val currentData = mutableListOf<T>() private var disposable: Disposable? = null fun refresh() = currentState.refresh() fun loadNewPage() = currentState.loadNewPage() fun release() = currentState.release() //... }
  10. private inner class EMPTY : State<T> { override fun refresh()

    { currentState = EMPTY_PROGRESS() viewController.showEmptyProgress(true) loadPage(FIRST_PAGE) } override fun release() { currentState = RELEASED() disposable?.dispose() } }
  11. override fun onFirstViewAttach() { refreshIssues() } override fun onDestroy() {

    paginator.release() } fun refreshIssues() = paginator.refresh() fun loadNextIssuesPage() = paginator.loadNewPage()