Search code examples
androidpagedlistmutablelivedataandroid-romandroid-pagedlistview

MutableLiveData won't trigger loadAfter to fetch from Android ROM using PagedList


I have 70 itens stored on my ROM and I would like to fetch a paged amount of 15. I read many posts so far with related issues, however none of them were useful for me.

Some possible causes for loadAfter not being triggered:

Solution 1 : call getItem inside onBindViewHolder

Solution 2 : call submitList to PagedListAdapter

Solution 3 : replace ListAdapter with PagedListAdapter

I assume DataBinding is fine since everything works without trying to paging.

I'm mocking my data source to understand what's happening. Some functions are suspended 'cause they should have data coming from ROM which requires it. My code state be like:

ADAPTER

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    getItem(position).let { wkda ->
        with(holder) {
            wkda?.apply { bind(createOnClickListener(this)) }
        }
    }
}

FRAGMENT

vm.manufacturers.observe(viewLifecycleOwner) { manufacturers ->            
            adapter.submitList(manufacturers)
}

VIEWMODEL

var manufacturers: MutableLiveData<PagedList<WKDA>> = MutableLiveData()

init {
  viewModelScope.launch {
    repository.getManufacturers(manufacturers)
  }
}

REPOSITORY

suspend fun getManufacturers(manufacturers: MutableLiveData<PagedList<WKDA>>) {
        withContext(Dispatchers.IO) {
            manufacturers.postValue(ManufacturerPagedList.
                getInstance().
                fetchPage())
        }
}

MANUFACTURER PAGED LIST

private val executor = ManufacturerExecutor()

private val paginationConfig: PagedList.Config = PagedList.Config.Builder()
        .setPageSize(PAGE_SIZE)
        .setPrefetchDistance(FETCH_DISTANCE)
        .setEnablePlaceholders(false)
        .build()

companion object {
        @Volatile
        private var instance: ManufacturerPagedList? = null
            fun getInstance() = instance ?: synchronized(this) {
                ManufacturerPagedList().also {
                    instance = it
                }
        }
    }

fun fetchPage(): PagedList<WKDA> = PagedList.Builder<Int, WKDA>(
            MockDataSource(),
            paginationConfig)
            .setInitialKey(INITIAL_KEY)
            .setFetchExecutor(executor)
            .setNotifyExecutor(executor)
            .build()
}

DATASOURCE

class MockDataSource : PageKeyedDataSource<Int, WKDA>() {
    override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, WKDA>) {
        callback.onResult(List(20) { generatePost(params.requestedLoadSize) }.toList(), -1, 1)
    }

    override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, WKDA>) {
        callback.onResult(List(20) { generatePost(params.key) }.toList(), params.key + 1)
    }

    override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, WKDA>) {
        callback.onResult(List(20) { generatePost(params.key) }.toList(), params.key - 1)
    }

    private fun generatePost(key: Int): WKDA {
        return WKDA("name", "author $key")
    }
}

CONSTANTS

const val INITIAL_KEY: Int = 0
const val PAGE_SIZE: Int = 15
const val FETCH_DISTANCE: Int = 1

What am I missing here?


Solution

  • After check: loadAfter was called properly. The problem was model itself:

    wkda.id had always the same "name" value

    DiffCallback compared old list of objects with the new one and didn't see differences, so the item "duplicates" weren't added to the adapter