[英]Paging Library invalidating data source not working
最近我試過這個:
我有一個由數據源支持的作業列表(我正在使用分頁庫),作業列表中的每個項目都有一個保存按鈕,該保存按鈕將作業的狀態從未保存更新為保存(或反之亦然)在數據庫中並且一旦更新它就會使DataSource無效,現在無效應該立即導致當前頁面的重新加載,但是沒有發生。
我檢查了數據庫中的值,它們實際上已經更新,但UI不是這種情況。
碼:
public class JobsPagedListProvider {
private JobListDataSource<JobListItemEntity> mJobListDataSource;
public JobsPagedListProvider(JobsRepository jobsRepository) {
mJobListDataSource = new JobListDataSource<>(jobsRepository);
}
public LivePagedListProvider<Integer, JobListItemEntity> jobList() {
return new LivePagedListProvider<Integer, JobListItemEntity>() {
@Override
protected DataSource<Integer, JobListItemEntity> createDataSource() {
return mJobListDataSource;
}
};
}
public void setQueryFilter(String query) {
mJobListDataSource.setQuery(query);
}
}
這是我的自定義數據源:
public class JobListDataSource<T> extends TiledDataSource<T> {
private final JobsRepository mJobsRepository;
private final InvalidationTracker.Observer mObserver;
String query = "";
@Inject
public JobListDataSource(JobsRepository jobsRepository) {
mJobsRepository = jobsRepository;
mJobsRepository.setJobListDataSource(this);
mObserver = new InvalidationTracker.Observer(JobListItemEntity.TABLE_NAME) {
@Override
public void onInvalidated(@NonNull Set<String> tables) {
invalidate();
}
};
jobsRepository.addInvalidationTracker(mObserver);
}
@Override
public boolean isInvalid() {
mJobsRepository.refreshVersionSync();
return super.isInvalid();
}
@Override
public int countItems() {
return DataSource.COUNT_UNDEFINED;
}
@Override
public List<T> loadRange(int startPosition, int count) {
return (List<T>) mJobsRepository.getJobs(query, startPosition, count);
}
public void setQuery(String query) {
this.query = query;
}
}
以下是JobsRepository中的代碼,用於將作業從未保存更新為已保存:
public void saveJob(JobListItemEntity entity) {
Completable.fromCallable(() -> {
JobListItemEntity newJob = new JobListItemEntity(entity);
newJob.isSaved = true;
mJobDao.insert(newJob);
Timber.d("updating entity from " + entity.isSaved + " to "
+ newJob.isSaved); //this gets printed in log
//insertion in db is happening as expected but UI is not receiving new list
mJobListDataSource.invalidate();
return null;
}).subscribeOn(Schedulers.newThread()).subscribe();
}
這是作業列表的差異邏輯:
private static final DiffCallback<JobListItemEntity> DIFF_CALLBACK = new DiffCallback<JobListItemEntity>() {
@Override
public boolean areItemsTheSame(@NonNull JobListItemEntity oldItem, @NonNull JobListItemEntity newItem) {
return oldItem.jobID == newItem.jobID;
}
@Override
public boolean areContentsTheSame(@NonNull JobListItemEntity oldItem, @NonNull JobListItemEntity newItem) {
Timber.d(oldItem.isSaved + " comp with" + newItem.isSaved);
return oldItem.jobID == newItem.jobID
&& oldItem.jobTitle.compareTo(newItem.jobTitle) == 0
&& oldItem.isSaved == newItem.isSaved;
}
};
JobRepository中的JobListDataSource(下面僅提到相關部分):
public class JobsRepository {
//holds an instance of datasource
private JobListDataSource mJobListDataSource;
//setter
public void setJobListDataSource(JobListDataSource jobListDataSource) {
mJobListDataSource = jobListDataSource;
}
}
JobsRepository中的getJobs():
public List<JobListItemEntity> getJobs(String query, int startPosition, int count) {
if (!isJobListInit) {
Observable<JobList> jobListObservable = mApiService.getOpenJobList(
mRequestJobList.setPageNo(startPosition/count + 1)
.setMaxResults(count)
.setSearchKeyword(query));
List<JobListItemEntity> jobs = mJobDao.getJobsLimitOffset(count, startPosition);
//make a synchronous network call since we have no data in db to return
if(jobs.size() == 0) {
JobList jobList = jobListObservable.blockingSingle();
updateJobList(jobList, startPosition);
} else {
//make an async call and return cached version meanwhile
jobListObservable.subscribe(new Observer<JobList>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(JobList jobList) {
updateJobList(jobList, startPosition);
}
@Override
public void onError(Throwable e) {
Timber.e(e);
}
@Override
public void onComplete() {
}
});
}
}
return mJobDao.getJobsLimitOffset(count, startPosition);
}
jobsRepository中的updateJobList:
private void updateJobList(JobList jobList, int startPosition) {
JobListItemEntity[] jobs = jobList.getJobsData();
mJobDao.insert(jobs);
mJobListDataSource.invalidate();
}
在閱讀了DataSource的源代碼后,我意識到了這一點:
invalidate()
表示:如果已經調用了invalidate,則此方法不執行任何操作。 我實際上有一個由JobsPagedListProvider
提供的自定義DataSource( JobListDataSource
)的單例,所以當我在saveJob()
(在JobsRepository
定義saveJob()
我的DataSource
無效時,它試圖獲取新的DataSource
實例(通過再次調用來獲取最新數據) loadRange() - 這就是DataSource工作的清新程度)但是因為我的DataSource
是單例並且它已經無效所以沒有進行loadRange()
查詢!
因此,請確保您沒有單獨的DataSource
並手動使您的DataSource
無效(通過調用invalidate()
)或在DataSource的構造函數中使用InvalidationTracker
。
所以最終的解決方案是這樣的:
在JobsPagedListProvider中沒有單例:
public class JobsPagedListProvider {
private JobListDataSource<JobListItemEntity> mJobListDataSource;
private final JobsRepository mJobsRepository;
public JobsPagedListProvider(JobsRepository jobsRepository) {
mJobsRepository = jobsRepository;
}
public LivePagedListProvider<Integer, JobListItemEntity> jobList() {
return new LivePagedListProvider<Integer, JobListItemEntity>() {
@Override
protected DataSource<Integer, JobListItemEntity> createDataSource() {
//always return a new instance, because if DataSource gets invalidated a new instance will be required(that's how refreshing a DataSource works)
mJobListDataSource = new JobListDataSource<>(mJobsRepository);
return mJobListDataSource;
}
};
}
public void setQueryFilter(String query) {
mJobListDataSource.setQuery(query);
}
}
還要確保如果從網絡獲取數據,則需要具有正確的邏輯,以便在查詢網絡之前檢查數據是否過時,否則每次DataSource失效時它都會重新查詢。 我通過具有在insertedAt字段解決它JobEntity
以跟蹤時,該產品在插入DB的並檢查它是否在陳舊getJobs()
的JobsRepository
。
以下是getJobs()的代碼:
public List<JobListItemEntity> getJobs(String query, int startPosition, int count) {
Observable<JobList> jobListObservable = mApiService.getOpenJobList(
mRequestJobList.setPageNo(startPosition / count + 1)
.setMaxResults(count)
.setSearchKeyword(query));
List<JobListItemEntity> jobs = mJobDao.getJobsLimitOffset(count, startPosition);
//no data in db, make a synchronous call to network to get the data
if (jobs.size() == 0) {
JobList jobList = jobListObservable.blockingSingle();
updateJobList(jobList, startPosition, false);
} else if (shouldRefetchJobList(jobs)) {
//data available in db, so show a cached version and make async network call to update data
jobListObservable.subscribe(new Observer<JobList>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(JobList jobList) {
updateJobList(jobList, startPosition, true);
}
@Override
public void onError(Throwable e) {
Timber.e(e);
}
@Override
public void onComplete() {
}
});
}
return mJobDao.getJobsLimitOffset(count, startPosition);
}
最后刪除JobListDatasource中的InvalidationTracker,因為我們手動處理失效:
public class JobListDataSource<T> extends TiledDataSource<T> {
private final JobsRepository mJobsRepository;
String query = "";
public JobListDataSource(JobsRepository jobsRepository) {
mJobsRepository = jobsRepository;
mJobsRepository.setJobListDataSource(this);
}
@Override
public int countItems() {
return DataSource.COUNT_UNDEFINED;
}
@Override
public List<T> loadRange(int startPosition, int count) {
return (List<T>) mJobsRepository.getJobs(query, startPosition, count);
}
public void setQuery(String query) {
this.query = query;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.