How to notify Dataset changed for RecyclerView

How to notify Dataset changed for RecyclerView

Think about a better way to notify dataset changed for RecyclerView.

51599b694b52e34258f54a98257036b9?s=128

Ryota Takemoto

February 27, 2018
Tweet

Transcript

  1. 13.

    adapter.getDataSet().removeAt(position) adapter.notifyItemRemoved(position) adapter.notifyItemRangeChanged( position, adapter.itemCount - position ) // ok

    adapter.getDataSet().removeAt(position2) adapter.notifyItemRemoved(position2) adapter.notifyItemRangeChanged(…) // ok notifyItem~()
  2. 14.

    Ideal • Easy to use • Redraw only changed items

    • Multiple item notifying • Animation Adapter.notify~()
  3. 15.
  4. 16.

    DiffUtil • Support Lib 25.1.0~ • Calculate diff between 2

    list • Notify only changed items • Animation DiffUtil
  5. 19.

    DiffUtil.Callback override fun getOldListSize() = oldList.size override fun getNewListSize() =

    newList.size // Same item? override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean { return oldList[oldPos].id == newList[newPos].id } // Any changes? override fun areContentsTheSame(oldPos: Int, newPos: Int): Boolean { val old = oldList[oldPos] val new = newList[newPos] return old == new } Implementation For DiffUtil
  6. 23.

    Full Implementation val diffCallback = object : DiffUtil.Callback() { val

    oldList = currentDataSet val newList = newDataSet override fun getOldListSize() = oldList.size override fun getNewListSize() = newList.size override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean = oldList[oldPos].id == newList[newPos].id override fun areContentsTheSame(oldPos: Int, newPos: Int): Boolean = oldList[oldPos] == newList[newPos] } val diffResult = DiffUtil.calculateDiff(diffCallback) diffResult.dispatchUpdatesTo(adapter)
  7. 27.

    Calculate diff on background “If the lists are large, this

    operation may take significant time” “run this on a background thread, get the DiffUtil.DiffResult then apply it on the main thread” Implementation For DiffUtil
  8. 28.

    Calculate diff on background Thread({ val diffCallback = object :

    DiffUtil.Callback() { … } // Calculate diff on background thread. val diffResult = DiffUtil.calculateDiff(diffCallback) handler.post { // Update on main thread. diffResult.dispatchUpdatesTo(adapter) } }).start()
  9. 29.

    Calculate diff on background Thread({ val diffCallback = object :

    DiffUtil.Callback() { … } // Calculate diff on background thread. val diffResult = DiffUtil.calculateDiff(diffCallback) handler.post { // Update on main thread. diffResult.dispatchUpdatesTo(adapter) } }).start()
  10. 30.

    Calculate diff on background Thread({ val diffCallback = object :

    DiffUtil.Callback() { … } // Calculate diff on background thread. val diffResult = DiffUtil.calculateDiff(diffCallback) handler.post { // Update on main thread. diffResult.dispatchUpdatesTo(adapter) } }).start()
  11. 32.

    Paging Library Paging Library • Part of AAC • Having

    same feature as DiffUtil • Paging
  12. 38.

    class PageKeyedRepoDataSource: PageKeyedDataSource<Int, Repo>() { override fun loadInitial(params: LoadInitialParams<Int>, callback:

    LoadInitialCallback<Int, Repo>) { // Initial data fetching } override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, Repo>) { // no-op } override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, Repo>) { // Paged data fetching } }
  13. 39.

    override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, Repo>) { val page

    = 1 val nextPageKey = 2 val response = repoApiClient .getRepos(USER_NAME, page, params.requestedLoadSize) .execute() callback.onResult(response.body(), null, nextPageKey) }
  14. 40.

    override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, Repo>) { val page

    = params.key val nextPageKey = params.key + 1 val response = repoApiClient .getRepos(USER_NAME, page, params.requestedLoadSize) .execute() callback.onResult(response.body(), nextPageKey) }
  15. 42.
  16. 44.

    val dataSourceFactory = RepoDataFactory(repoApiClient) val config = PagedList.Config.Builder() .setInitialLoadSizeHint(10) .setPageSize(10)

    .build() return LivePagedListBuilder(dataSourceFactory, config) .setBackgroundThreadExecutor(NETWORK_IO) .build()
  17. 45.

    private fun getRepos(): LiveData<PagedList<Repo>> { ... } getRepos() .observe(context, Observer

    { pagedList -> // Items are drawn pagedListAdapter.setList(pagedList) }) Observe PagedList
  18. 46.

    Update DataSet Implementation for Paging Library • Re-fetch API with

    sort condition • Update items only changed by setting PagedList again
  19. 47.

    private fun getRepos(condition: SortCondition) : LiveData<PagedList<Repo>> { ... } getRepos(SortCondition.UPDATED)

    .observe(context, Observer { pagedList -> // Only new items are drawn repoAdapter.setList(pagedList) })
  20. 48.

    private fun getRepos(condition: SortCondition) : LiveData<PagedList<Repo>> { ... } getRepos(SortCondition.UPDATED)

    .observe(context, Observer { pagedList -> repoAdapter.setList(null) // All new items are redrawn repoAdapter.setList(pagedList) })
  21. 49.