分页库 Filter/Search
Paging Library Filter/Search
我正在使用 Android 分页库,如下所述:
https://developer.android.com/topic/libraries/architecture/paging.html
但我还有一个 EditText 用于按名称搜索用户。
如何过滤 Paging 库中的结果以仅显示匹配的用户?
您可以使用 MediatorLiveData 解决这个问题。
具体来说Transformations.switchMap
.
// original code, improved later
public void reloadTasks() {
if(liveResults != null) {
liveResults.removeObserver(this);
}
liveResults = getFilteredResults();
liveResults.observeForever(this);
}
不过仔细想想,不用observeForever
应该也能解决这个问题,尤其是考虑到switchMap
也在做类似的事情。
所以我们需要的是 LiveData<SelectedOption>
,即 switch-mapped 到我们需要的 LiveData<PagedList<T>>
。
private final MutableLiveData<String> filterText = savedStateHandle.getLiveData("filterText")
private final LiveData<List<T>> data;
public MyViewModel() {
data = Transformations.switchMap(
filterText,
(input) -> {
if(input == null || input.equals("")) {
return repository.getData();
} else {
return repository.getFilteredData(input); }
}
});
}
public LiveData<List<T>> getData() {
return data;
}
这样,从一个到另一个的实际更改由 MediatorLiveData 处理。
我使用了类似于 EpicPandaForce 回答的方法。虽然它正在工作,但这个 subscribing/unsubscribing 看起来很乏味。我已经开始使用 Room 之外的另一个数据库,所以无论如何我都需要创建自己的 DataSource.Factory。显然,可以使当前数据源无效并 DataSource.Factory 创建一个新的数据源,这就是我使用搜索参数的地方。
我的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,但您可以 return 在创建时查询您的房间 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。它在工厂中设置搜索查询,然后使数据源无效。反过来,在工厂中调用 create 并使用新查询创建 DataSource 的新实例并传递给引擎盖下的现有 LiveData..
您可以使用上面的其他答案,但这里有另一种方法:您可以让工厂根据您的需求生成不同的数据源。这是如何完成的:
在您的 DataSource.Factory class 中,为初始化 YourDataSource
所需的参数提供设置器
private String searchText;
...
public void setSearchText(String newSearchText){
this.searchText = newSearchText;
}
@NonNull
@Override
public DataSource<Integer, SearchItem> create() {
YourDataSource dataSource = new YourDataSource(searchText); //create DataSource with parameter you provided
return dataSource;
}
当用户输入新的搜索文本时,让您的 ViewModel class 设置新的搜索文本,然后在 DataSource 上调用 invalidated。在你的 Activity/Fragment:
yourViewModel.setNewSearchText(searchText); //set new text when user searchs for a text
在您的 ViewModel 中,定义更新工厂 class 的搜索文本的方法:
public void setNewSearchText(String newText){
//you have to call this statement to update the searchText in yourDataSourceFactory first
yourDataSourceFactory.setSearchText(newText);
searchPagedList.getValue().getDataSource().invalidate(); //notify yourDataSourceFactory to create new DataSource for searchPagedList
}
当DataSource 失效时,DataSource.Factory 将调用其create() 方法使用您设置的newText 值创建新的DataSource。结果将相同
我正在使用 Android 分页库,如下所述: https://developer.android.com/topic/libraries/architecture/paging.html
但我还有一个 EditText 用于按名称搜索用户。
如何过滤 Paging 库中的结果以仅显示匹配的用户?
您可以使用 MediatorLiveData 解决这个问题。
具体来说Transformations.switchMap
.
// original code, improved later
public void reloadTasks() {
if(liveResults != null) {
liveResults.removeObserver(this);
}
liveResults = getFilteredResults();
liveResults.observeForever(this);
}
不过仔细想想,不用observeForever
应该也能解决这个问题,尤其是考虑到switchMap
也在做类似的事情。
所以我们需要的是 LiveData<SelectedOption>
,即 switch-mapped 到我们需要的 LiveData<PagedList<T>>
。
private final MutableLiveData<String> filterText = savedStateHandle.getLiveData("filterText")
private final LiveData<List<T>> data;
public MyViewModel() {
data = Transformations.switchMap(
filterText,
(input) -> {
if(input == null || input.equals("")) {
return repository.getData();
} else {
return repository.getFilteredData(input); }
}
});
}
public LiveData<List<T>> getData() {
return data;
}
这样,从一个到另一个的实际更改由 MediatorLiveData 处理。
我使用了类似于 EpicPandaForce 回答的方法。虽然它正在工作,但这个 subscribing/unsubscribing 看起来很乏味。我已经开始使用 Room 之外的另一个数据库,所以无论如何我都需要创建自己的 DataSource.Factory。显然,可以使当前数据源无效并 DataSource.Factory 创建一个新的数据源,这就是我使用搜索参数的地方。
我的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,但您可以 return 在创建时查询您的房间 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。它在工厂中设置搜索查询,然后使数据源无效。反过来,在工厂中调用 create 并使用新查询创建 DataSource 的新实例并传递给引擎盖下的现有 LiveData..
您可以使用上面的其他答案,但这里有另一种方法:您可以让工厂根据您的需求生成不同的数据源。这是如何完成的: 在您的 DataSource.Factory class 中,为初始化 YourDataSource
所需的参数提供设置器private String searchText;
...
public void setSearchText(String newSearchText){
this.searchText = newSearchText;
}
@NonNull
@Override
public DataSource<Integer, SearchItem> create() {
YourDataSource dataSource = new YourDataSource(searchText); //create DataSource with parameter you provided
return dataSource;
}
当用户输入新的搜索文本时,让您的 ViewModel class 设置新的搜索文本,然后在 DataSource 上调用 invalidated。在你的 Activity/Fragment:
yourViewModel.setNewSearchText(searchText); //set new text when user searchs for a text
在您的 ViewModel 中,定义更新工厂 class 的搜索文本的方法:
public void setNewSearchText(String newText){
//you have to call this statement to update the searchText in yourDataSourceFactory first
yourDataSourceFactory.setSearchText(newText);
searchPagedList.getValue().getDataSource().invalidate(); //notify yourDataSourceFactory to create new DataSource for searchPagedList
}
当DataSource 失效时,DataSource.Factory 将调用其create() 方法使用您设置的newText 值创建新的DataSource。结果将相同