我使用了类似于 EpicPandaForce 回答的方法。虽然它正在工作,但这种订阅/取消订阅似乎很乏味。我已经开始使用其他数据库而不是 Room,所以无论如何我都需要创建自己的 DataSource.Factory。显然,可以使当前的 DataSource 无效,并且 DataSource.Factory 创建一个新的 DataSource,这就是我使用搜索参数的地方。
我的 DataSource.Factory:
class SweetSearchDataSourceFactory(private val box: Box<SweetDb>) :
DataSource.Factory<Int, SweetUi>() {
var query = ""
override fun create(): DataSource<Int, SweetUi> {
val lazyList = box.query().contains(SweetDb_.name, query).build().findLazyCached()
return SweetSearchDataSource(lazyList).map { SweetUi(it) }
}
fun search(text: String) {
query = text
}
}
我在这里使用 ObjectBox,但你可以在创建时返回你的房间 DAO 查询(我猜它已经是一个 DataSourceFactory,调用它自己的创建)。
我没有测试它,但这可能有效:
class SweetSearchDataSourceFactory(private val dao: SweetsDao) :
DataSource.Factory<Int, SweetUi>() {
var query = ""
override fun create(): DataSource<Int, SweetUi> {
return dao.searchSweets(query).map { SweetUi(it) }.create()
}
fun search(text: String) {
query = text
}
}
当然,可以通过来自 dao 的查询传递一个工厂。
视图模型:
class SweetsSearchListViewModel
@Inject constructor(
private val dataSourceFactory: SweetSearchDataSourceFactory
) : BaseViewModel() {
companion object {
private const val INITIAL_LOAD_KEY = 0
private const val PAGE_SIZE = 10
private const val PREFETCH_DISTANCE = 20
}
lateinit var sweets: LiveData<PagedList<SweetUi>>
init {
val config = PagedList.Config.Builder()
.setPageSize(PAGE_SIZE)
.setPrefetchDistance(PREFETCH_DISTANCE)
.setEnablePlaceholders(true)
.build()
sweets = LivePagedListBuilder(dataSourceFactory, config).build()
}
fun searchSweets(text: String) {
dataSourceFactory.search(text)
sweets.value?.dataSource?.invalidate()
}
}
无论接收到搜索查询,只需在 ViewModel 上调用 searchSweets。它在工厂中设置搜索查询,然后使数据源无效。反过来,在 Factory 中调用 create 并使用新查询创建 DataSource 的新实例,并在后台传递给现有的 LiveData..