最近我在尝试这个:
我有一个由数据源支持的作业列表(我正在使用分页库),作业列表中的每个项目都有一个保存按钮,该保存按钮将作业的状态从未保存更新为保存(反之亦然) )在数据库中,一旦更新,它就会使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();
}
答案 0 :(得分:2)
在阅读了DataSource的源代码后,我意识到了这一点:
"themeColor"===field.name && (field.disabled=this.isV1User?!1:
this.user.customSetting?!this.user.customSetting.themePicker:!1);
说:如果已经调用了invalidate,则此方法不执行任何操作。我实际上拥有invalidate()
提供的自定义数据源(JobListDataSource
)的单例,因此当我在JobsPagedListProvider
中DataSource
无效时(在{{中定义) 1}}),它试图获得新的saveJob()
实例(通过再次调用loadRange()获取最新数据 - 这就是DataSource的工作原理)
但由于我的JobsRepository
是单身,而且它已经无效,因此没有DataSource
查询!
因此,请确保您没有DataSource
的单身,并且手动(通过调用loadRange()
)或在您的DataSource的构造函数中拥有DataSource
使DataSource
无效
所以最终解决方案是这样的:
在JobsPagedListProvider中没有单例:
invalidate()
还要确保从网络中获取数据,您需要拥有正确的逻辑,以便在查询网络之前检查数据是否过时,否则每次DataSource失效时它都会重新查询。
我通过InvalidationTracker
中的insertedAt字段解决了这个问题,该字段跟踪此项目在数据库中的插入时间,并检查它是否在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);
}
}
JobEntity
中过时。
以下是getJobs()的代码:
getJobs()
最后删除JobListDatasource中的InvalidationTracker,因为我们正在手动处理失效:
JobsRepository