androidandroid-recyclerviewpagedlist

PagingLibrary (LivePageListBuilder) does not not return PagedData


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
  }

}

Solution

  • 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