问题
I am having activity that displays list of items and also having filter and search option. I am displaying the items using android paging library. First time the List of items will be loaded its working fine when I am Scrolling to bottom next set of items getting loaded. But I also want to filter the items and Search the items. On Filtering or Searching item I am invalidating the existing source.if am not invalidate the Data Source the filter and Search api is not firing.I want to load list of new items based on my filter and Search key using Data Source.
executor = Executors.newFixedThreadPool(5);
celebrityDataFactory = new CelebrityDataFactory(apicallInterface, mFansismParam);
networkState = Transformations.switchMap(celebrityDataFactory.getCelebrityData(),
dataSource -> dataSource.getNetworkState());
PagedList.Config pagedListConfig =
(new PagedList.Config.Builder())
.setEnablePlaceholders(false)
.setPrefetchDistance(8)
.setInitialLoadSizeHint(10)
.setPageSize(20).build();
if (!mFansismParam.getCategoryId().isEmpty()) {
celebrityDetails = new LivePagedListBuilder(celebrityDataFactory, pagedListConfig)
.setFetchExecutor(executor)
.build();
} else(!mFansismParam.getProfessionId().isEmpty()) {
celebrityDetails = new LivePagedListBuilder(celebrityDataFactory, pagedListConfig)
.setFetchExecutor(executor)
.build();
}
Data Factory to create Data Source
@Override
public DataSource create() {
celebrityDataSource = new CelebrityDataSource(apicallInterface, params);
celebrityData.postValue(celebrityDataSource);
return celebrityDataSource;
}
Retrofit API Call:
Call<CelebrityList> getCelebrityList(@Query("categoryId") String categoryId,
@Query("professionId") String professionId,
@Query("page") String pageNumber,
@Query("name") String searchKey);
Data Source Api CallBack:
apicallInterface.getCelebrityList(requestParams.getCategoryId(), "", "1", "").enqueue(new Callback<CelebrityList>() {
@Override
public void onResponse(Call<CelebrityList> call, Response<CelebrityList> response) {
if (response.isSuccessful()) {
initialLoading.postValue(NetworkState.LOADED);
networkState.postValue(NetworkState.LOADED);
if (!response.body().getData().isEmpty()) {
callback.onResult(response.body().getData(), null, "2");
} else {
networkState.postValue(new NetworkState(NetworkState.Status.SUCCESS, "No more results"));
}
} else {
initialLoading.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
networkState.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
}
}
回答1:
You need to hold your search key in live data so that pagedlist can be changed whenever it changes. So in your viewmodel, define:
public MutableLiveData<String> filterTextAll = new MutableLiveData<>();
Since the pagedlist is defined as a LiveData too, this can be done with the help of Transformation. Transformations class provide you with functions with which you can change the value in your LiveData object. swithMap function returns a new LiveData object rather than a value, in your case, searchkey is switched to get the pagedList object corresponding to the searchkey by create new datasource under the hood.
pagedListLiveData = Transformations.switchMap(filterTextAll, input -> {
MyDataSourceFactory myDataSourceFactory = new MyDataSourceFactory(executor,input);
myDataSource = myDataSourceFactory.getMyDataSourceMutableLiveData();
networkState = Transformations.switchMap(myDataSource,
dataSource -> dataSource.getNetworkState());
return (new LivePagedListBuilder(myDataSourceFactory, pagedListConfig))
.setFetchExecutor(executor)
.build();
});
You can to change your DataSourceFactory and DataSource constructor to add searchKey param:
public class MyDataSourceFactory extends DataSource.Factory {
MutableLiveData<MyDataSource> myDataSourceMutableLiveData;
private MyDataSource myDataSource;
private Executor executor;
private String searchKey;
public MyDataSourceFactory(Executor executor , String searchKey) {
this.executor= executor;
this.searchKey= searchKey;
this.myDataSourceMutableLiveData= new MutableLiveData<>();
}
@Override
public DataSource create() {
//*notice: It's important that everytime a DataSource factory create() is invoked a new DataSource instance is created
myDataSource= new MyDataSource(executor, searchKey);
myDataSourceMutableLiveData.postValue(myDataSource);
return myDataSource;
}
public MutableLiveData<MyDataSource> getMyDataSourceMutableLiveData() {
return myDataSourceMutableLiveData;
}
public MyDataSource getMyDataSource() {
return myDataSource;
}
}
do same like above for DataSource constructor to pass searchKey to use in api call. And one thing remains, in your Activity/Fragment (lifeCycleOwner) set value of filterTextAll mutableLiveData whenever searchkey change fired, like trigger searchview onQueryTextChange or any event you like.
private void performSearch(String searchKey) {
// TODO: Perform the search and update the UI to display the results.
myViewModel.filterTextAll.setValue(searchKey);
myViewModel.pagedListLiveData.observe(owner, new Observer<PagedList<MyItem>>() {
@Override
public void onChanged(PagedList<MyItem> myItems) {
myAdapter.submitList(myItems);
}
});
myViewModel.networkState.observe(owner, new Observer<NetworkState>() {
@Override
public void onChanged(NetworkState networkState) {
myAdapter.setNetworkState(networkState);
}
});
myRecyclerView.setAdapter(myAdapter);
}
来源:https://stackoverflow.com/questions/57841020/how-to-maintain-same-datasource-for-list-filter-and-search-in-android-paging-lib