分页库使数据源无效

时间:2017-10-17 15:39:34

标签: android android-architecture-components

最近我在尝试这个:

我有一个由数据源支持的作业列表(我正在使用分页库),作业列表中的每个项目都有一个保存按钮,该保存按钮将作业的状态从未保存更新为保存(反之亦然) )在数据库中,一旦更新,它就会使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();
}

1 个答案:

答案 0 :(得分:2)

在阅读了DataSource的源代码后,我意识到了这一点:

  1. 一旦失效,DataSource将永远无效。
  2. "themeColor"===field.name && (field.disabled=this.isV1User?!1: this.user.customSetting?!this.user.customSetting.themePicker:!1); 说:如果已经调用了invalidate,则此方法不执行任何操作。
  3. 我实际上拥有invalidate()提供的自定义数据源(JobListDataSource)的单例,因此当我在JobsPagedListProviderDataSource无效时(在{{中定义) 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