I'm using the Android Paging Library and I am having trouble getting results back from my DataSource.
I am basically getting an empty LiveData from my LivePagedListBuilder. Not sure what I am doing wrong. My loadInitial is also never called.
Here is my ViewModel:
class WorkPackagesViewModel: ViewModel() {
companion object {
const val PAGING_LIMIT_DEFAULT = 10
}
var workPackages: LiveData<PagedList<WorkPackagesQuery.WorkPackage>>? = null
fun fetchWorkPackages(isOnline: Boolean, workWeeK: Configurations.AppWeek, pagingStart: Int?, pagingLimit: Int?) {
val myConfig = PagedList.Config.Builder()
.setInitialLoadSizeHint(pagingLimit ?: PAGING_LIMIT_DEFAULT)
.setPageSize(pagingLimit ?: PAGING_LIMIT_DEFAULT )
.build()
val workPackageDataFactory = WorkPackageDataFactory(workWeeK)
workPackageDataFactory.create()
workPackages = LivePagedListBuilder(workPackageDataFactory, myConfig)
.setInitialLoadKey(pagingStart)
.setFetchExecutor(Executors.newFixedThreadPool(5))
.build()
}
}
}
Here is my DataSource.Factory:
class WorkPackageDataFactory(
private val workWeek : Configurations.AppWeek
) : DataSource.Factory<Int, WorkPackagesQuery.WorkPackage>() {
private var mutableLiveData: MutableLiveData<WorkPackageDataSource>? = MutableLiveData()
override fun create(): DataSource<Int, WorkPackagesQuery.WorkPackage> {
val workPackageDataSource = WorkPackageDataSource(workWeek)
mutableLiveData?.postValue(workPackageDataSource)
return workPackageDataSource
}
}
Here is my datasource file:
class WorkPackageDataSource(
private val workWeek : Configurations.AppWeek
) : PageKeyedDataSource<Int, WorkPackagesQuery.WorkPackage>(), KoinComponent
{
val client : PipefighterApi by inject()
private var parentJob = Job()
private val coroutineContext: CoroutineContext get() = parentJob + Dispatchers.Main
private val scope = CoroutineScope(coroutineContext)
override fun loadInitial( //DOES NOT GET CALLED
params: LoadInitialParams<Int>,
callback: LoadInitialCallback<Int, WorkPackagesQuery.WorkPackage>
) {
scope.launch {
val workPackages = getWorkPackages(1,params.requestedLoadSize)?.workPackages() as MutableList<WorkPackagesQuery.WorkPackage>
callback.onResult(workPackages, null, params.requestedLoadSize + 1 )
}
}
override fun loadAfter(
params: LoadParams<Int>,
callback: LoadCallback<Int, WorkPackagesQuery.WorkPackage>
) {
scope.launch {
val workPackages = getWorkPackages(params.key,params.requestedLoadSize)?.workPackages() as MutableList<WorkPackagesQuery.WorkPackage>
var nextKey : Int? = null
if (params.key.plus(0) != workPackages.size) {
nextKey = params.key.plus(1)
}
callback.onResult(workPackages, nextKey )
}
}
override fun loadBefore(
params: LoadParams<Int>,
callback: LoadCallback<Int, WorkPackagesQuery.WorkPackage>
) {
}
suspend fun getWorkPackages(
initialPage : Int,
requestedLoadSize : Int
) : WorkPackagesQuery.Result? {
return withContext(Dispatchers.IO) {
async { client.workPackages(
workWeek.currentWeekStart(),
workWeek.currentWeekEnd(),
initialPage,
requestedLoadSize
) }.await().response
}
}
}
Here is my fragment
class WorkPackagesFragment : Fragment(), WorkPackagesRecyclerAdapter.OnClickWorkPackage {
companion object {
private const val VERTICAL_ITEM_SPACE = 30
const val PAGING_START = 1
const val PAGING_LIMIT = 10
}
private val workPackagesViewModel: WorkPackagesViewModel by viewModel()
private val mainViewModel : MainViewModel by sharedViewModel()
private val networkConnection: NetworkConnectionHelper by inject()
private lateinit var binding: FragmentWorkPackagesBinding
private lateinit var adapter: WorkPackagesRecyclerAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(
inflater,
com.bechtel.pf.R.layout.fragment_work_packages,
container,
false
)
mainViewModel.week.observe(this, Observer {
it ?: return@Observer
workPackagesViewModel.fetchWorkPackages(networkConnection.connected(), it, PAGING_START, PAGING_LIMIT)
})
binding.lifecycleOwner = viewLifecycleOwner
binding.viewModel = workPackagesViewModel
workPackagesViewModel.workPackages?.observe(this, Observer {
it ?: return@Observer
adapter = WorkPackagesRecyclerAdapter(this)
adapter.submitList(it)
binding.workPackagesRecyclerView.adapter = adapter
adapter.notifyDataSetChanged()
})
return binding.root
}
}
I don't see where workPackages
is observed, but I guess the problem is that you observe workPackages
BEFORE you call fetchWorkPackages()
. When fetchWorkPackages()
is called, it creates a new LiveData and assigns the new one to workPackages
. But you only observe to the old LiveData in workPackages
before, so this new one doesn't have any active observers and therefore it never trigger loadInitial()
You can try to put fetchWorkPackages()
in init {}
in ViewModel, or set observe
for workPackages
AFTER calling fetchWorkPackages()
in your Activity or Fragment