【问题标题】:Observe not called with LiveData<PagedList>观察未使用 LiveData<PagedList> 调用
【发布时间】:2019-10-11 12:40:55
【问题描述】:

我正在使用带有 Room 数据库的 PagedList 架构组件,我无法将结果返回到观察方法。

这是我的道:

@Dao
interface WorkPackageStorageDao {

    @Query("SELECT * from workpackages where id = :id")
    fun getById(id: String): Workpackage

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insert(workpackage: Workpackage)

    @Query("Select * from workpackages WHERE id LIKE '%' || :searchString || '%' order by :orderBy")
    fun searchWorkpackages(searchString : String, orderBy : String) : DataSource.Factory<Int, Workpackage>

    @Query("SELECT * FROM workpackages")
    fun searchWorkPackgesTest() : List<Workpackage>

    @Query("Select * from workpackages WHERE id LIKE '%' || :searchString || '%' order by :orderBy")
    fun searchWorkPackgesTestQuery(searchString : String, orderBy : String) : List<Workpackage>

    @Query("DELETE from workpackages")
    fun deleteAll()

}

我的仓库:

fun getAllWorkPackagesTestQuery() : List<Workpackage> {
    return workpackagesDao.searchWorkPackgesTestQuery("",SortedBy.WorkPackageNumber.type)
}

fun getAllWorkPackages() : DataSource.Factory<Int, Workpackage> {
    return getSortedAndSearchedWorkPackages("",
        SortedBy.WorkPackageNumber
    )
}

fun getSortedAndSearchedWorkPackages(searchString : String, sortBy: SortedBy) : DataSource.Factory<Int, Workpackage> {
    return workpackagesDao.searchWorkpackages(searchString,sortBy.type)
}

这是我的视图模型中的方法:

suspend fun fetchWorkPackagesInitial(
    workWeek: Configurations.AppWeek,
    pagingLimit: Int
) {

    coroutineScope {
        withContext(Dispatchers.IO) {
            val factory: DataSource.Factory<Int, Workpackage> =
                workPackageRepository.getAllWorkPackages()

            val pagedListBuilder =
                LivePagedListBuilder<Int, Workpackage>(factory, pagingLimit)
            workPackagesList = pagedListBuilder.build() 
            val list = workPackageRepository.getAllWorkPackagesTestQuery() //27 Items returned, query is fine. 
        }

    }
}

这是我的片段:

    mainViewModel.week.observe(this, Observer {
        it ?: return@Observer

        launch { workPackagesViewModel.fetchWorkPackagesInitial(it, PAGING_LIMIT) }

    })

    //Observe never called.  
    workPackagesViewModel.workPackagesList?.observe(this, Observer { wpList ->
        wpList ?: return@Observer

        adapter = WorkPackagesRecyclerAdapter(this)
        adapter.submitList(wpList)
        binding.workPackagesRecyclerView.adapter = adapter
        adapter.notifyDataSetChanged()

    })

作为对我的查询的测试,我实现了:

val list = workPackageRepository.getAllWorkPackagesTestQuery() 

返回 27 个项目,所以查询没问题。我是不是设置了 Dao 错了,LivePagedListBuilder 错了?为什么不调用观察?

【问题讨论】:

  • 没有理由在 IO 上下文中获取分页列表数据源工厂。
  • @EpicPandaForce 不确定你的意思?

标签: android datasource android-architecture-components android-livedata pagedlist


【解决方案1】:

您没有收到物品,因为它是 PagedList。您需要触发加载才能获取页面。

这就是为什么通过submitList 将PagedList 提供给PagedListAdapter 最终会加载数据。

当您使用 PagedListAdapter 时,您也不需要手动调用 adapter.notifyDataSetChanged(),因为 DiffUtil 会在内部处理它。


但是,您绝对应该在 UI 线程 (Dispatcher.MAIN) 上检索 DataSource.FactoryLivePagedListBuilderPagedList,因为线程是由 Paging lib 的 Room 集成在内部处理的。观察(并在未加载的元素上调用getItem()将触发加载,加载将由开箱即用的DataSource 异步执行。



Paging 的使用方式是这样的:

class MyViewModel(
    private val workPackageStorageDao: WorkPackageStorageDao
): ViewModel() {
    private val searchQuery: MutableLiveData<String> = MutableLiveData("")

    val workPackages: LiveData<PagedList<WorkPackage>> = Transformations.switchMap(searchQuery) { searchText ->
        val factory = workPackageStorageDao.searchWorkPackages(searchText, SortedBy.WorkPackageNumber)
        val pagedListBuilder = LivePagedListBuilder<Int, WorkPackage>(factory, pagingLimit)
        pagedListBuilder.build()
    }
}

然后在片段中:

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    // ... setup RecyclerView, etc

    viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java, viewModelFactory)
    viewModel.workPackages.observe(viewLifecycleOwner, Observer { pagedList ->
        adapter.submitList(pagedList)
    })
}

在适配器中:

class MyAdapter: PagedListAdapter<WorkPackage, MyAdapter.ViewHolder>(WorkPackage.ITEM_CALLBACK) {
     override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
         val workPackage = getItem(position)
         if(workPackage != null) {
             holder.bind(workPackage)
         }
     }
}

长话短说,这里不需要协程。使用分页库和 LiveData,它将加载到正确的线程上。

【讨论】:

  • 好像我得到了这些项目,只是我的观察没有被调用。请参阅我编辑的问题。
  • 试图在 Dispatchers.Main 上获取数据源给了我一个 IllegalStateException,顺便说一句。
  • 是的,因为你在它下面运行同步查询是没有任何原因的(考虑到你已经在使用它上面的分页库)。如果你不打电话给getAllWorkPackagesTestQuery(),它不会给你一个 ISE。
  • 正如我所说,如果您使用的是 Paging(内部异步),那么不要调用同步的 getAllWorkPackagesTestQuery
  • 似乎已修复它。非常感谢!
猜你喜欢
  • 2019-02-04
  • 2018-07-22
  • 1970-01-01
  • 2019-06-10
  • 1970-01-01
  • 1970-01-01
  • 2018-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多