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

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

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for GDG SPb GDG SPb
November 22, 2017

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

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

Avatar for GDG SPb

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()