簡體   English   中英

分頁庫使數據源無效

[英]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的源代碼后,我意識到了這一點:

  1. 一旦失效,DataSource將永遠不會再次生效。
  2. 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM