分页库使数据源无效不起作用

2024-01-08

最近我正在尝试这个:

我有一个由数据源支持的作业列表(我正在使用分页库),并且作业列表中的每个项目都有一个保存按钮,并且该保存按钮将数据库中作业的状态从未保存更新为已保存(反之亦然)一旦更新,它就会使数据源失效,现在失效应该会导致当前页面立即重新加载,但这种情况并没有发生。

我检查了数据库中的值,它们实际上已更新,但用户界面的情况并非如此。

Code:

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 中的 JobList:

private void updateJobList(JobList jobList, int startPosition) {
    JobListItemEntity[] jobs = jobList.getJobsData();
    mJobDao.insert(jobs);
    mJobListDataSource.invalidate();
}

阅读 DataSource 的源代码后我意识到:

  1. 数据源一旦失效将永远不会再次有效。
  2. invalidate()说:如果已经调用了 invalidate,则此方法不执行任何操作。

我实际上有一个自定义数据源的单例(JobListDataSource) 由...提供JobsPagedListProvider,所以当我使我的DataSource in saveJob()(定义于JobsRepository),它试图获得新的DataSource实例(通过再次调用 loadRange() 来获取最新数据 - 这就是刷新数据源的工作原理) 但自从我的DataSource是单例并且它已经无效所以没有loadRange()正在查询!

所以请确保你没有一个单例DataSource并使你的DataSource手动(通过调用invalidate())或有一个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);
}
}

还要确保如果您从网络获取数据,则需要有正确的逻辑来在查询网络之前检查数据是否过时,否则每次数据源失效时都会重新查询。 我通过在中添加一个 insertAt 字段解决了这个问题JobEntity它跟踪该项目何时插入数据库并检查它是否过时getJobs() of 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;
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

分页库使数据源无效不起作用 的相关文章

随机推荐

  • 关注有值的输入字段

    我专注于 jQuery 的输入字段 input text focus 输入字段中已有一些文本值 当我聚焦时 光标在最后一个字母之后闪烁 我如何将光标放在第一个字母之前 你可以使用我为你创建的这个小插件 修改自这个脚本 http blog v
  • 如何在CoordinatorLayout中的Viewpager下面获取Adview

    此刻AdView出现在里面ViewPager所以它会阻止应用程序中的内容 我怎样才能得到AdView出现在下面ViewPager而不是在里面 我试过把AdView in a RelativeLayout以下ViewPager但随后AdVie
  • 具有 CRUD 方法的类违反了单一职责原则?

    我试图理解单一责任原则 我有以下问题 单一职责原则 SRP 规定 永远不应该 班级变更的原因不止一个 通常我们的Resource Service和Repository类有 创建 读取 更新和删除方法 我们正在将每个班级更改为 修改任何这些操
  • BigQuery 下载或导出为 JSON 不考虑类型

    我在 BigQuery 中运行的查询 SELECT 5 as a 当我运行上述查询并选择时得到的架构另存为表格 当我将查询结果下载为 JSON 时得到的 JSONor当我导出表时 a 5 这不应该是 a 5 From 导出表数据 导出限制
  • C# Mysql - 在异步等待服务器的数据库查询上使用锁

    I have TcpListener类和我正在使用async await读写 对于该服务器 我创建了单个数据库实例 在其中准备了所有数据库查询 但对于不止一个TcpClient我不断遇到异常 类型异常MySql Data MySqlClie
  • 找不到模块“file-name.png”或其相应的类型声明 - Typescript React

    我正在尝试在我的打字稿反应项目中导入一个 png 如下所示 import logo from assets Logo svg 我收到了这个 TS 错误 Cannot find module assets Logo svg or its co
  • 为什么 Meteor 抱怨集合的插入方法已经定义了?

    谁能告诉我为什么下面的代码会抛出以下错误 Error A method named players insert is already defined 我是 Meteor 和 Coffeescript 的新手 所以我可能会忽略一些简单的东西
  • 在 Matlab 中使用单个校准图像校正镜头畸变

    我想纠正一系列图像的镜头畸变 所有图像都是用固定在适当位置的相机拍摄的 并且还可以使用同一设置的棋盘图像 检测到扭曲的棋盘图像的角点后 我想计算径向扭曲系数 以便我可以校正图像 类似于估计相机参数 http www mathworks co
  • 检测设备是否有 GPS

    如何检测GPS是否可用 iPod touch 和 iPad WiFi 版本没有 GPS 它们有基于 WiFi 的其他功能 无论如何 如何知道 GPS 是否可用 或者如何检测 iPod Touch 或 iPad Wifi 型号 这是 iOS
  • 无法从源 Pylance 解析导入“flask”(reportMissingModuleSource)

    当我写作时 from flask import Flask 一条黄线即将出现flask并说明无法从源 Pylance 解析导入 flask reportMissingModuleSource 另外 我也能够成功地使用这个包完成工作 但问题是
  • 如何在 R闪亮中显示多个.xpt文件并根据它们的列过滤它们?

    当我尝试上传多个 xpt 文件以在 R闪亮应用程序的主面板中显示表格时 它给我带来了以下问题 我也在寻找过滤选项 我想在上传多个文件时按列进行过滤 以便在每个数据框 数据表的主面板中显示适当的行 Error Warning Error in
  • ORM 和构造函数

    我正在研究 NET ORM 实现 并且有一个重要的紧迫问题 是否有任何 NET ORM 实现不需要数据库中每个字段的公共属性 当我看到这样的例子时this https web archive org web 20090831053827 h
  • Objective-C - 使用 GDB 打印方法参数

    我正在努力使用 GDB 调试我的 Objective C 程序 我有一个函数 NSString reverse NSString someString我想调试它 我设置断点的方法如下 gdb break MyClass reverse 现在
  • 如果当前行包含字符串,如何打印文件中的下一行?

    我正在尝试编写一些内容来打印文件中的某些行 假设该文件如下所示 name 1 name a name 2 name b name 3 extra 1 name c name 4 extra 1 name d 所以通常我可以做if line
  • 如何将动态外部组件加载到 Angular 应用程序中

    我在 Angular 应用程序中遇到问题 我想要一个用 Typescript 编写的角度应用程序 aot 目的是显示带有一些小部件的用户仪表板 小部件是一个角度组件 我的应用程序附带了一些嵌入式小部件 但小部件应该通过市场之类的东西来扩展
  • Elasticsearch:为什么我的查询返回太多结果?

    我正在查询http elasticsearch myserver net 9200 my index foo 使用以下查询 query ids type foo values fff bar baz 但我收到的响应有 12 个命中 这是我的
  • 并行计算右侧的连续零位(尾随):解释?

    考虑这个链接 http graphics stanford edu seander bithacks html ZerosOnRightParallel来自 Bit Twiddling Hacks 网站 为了计算尾随位 使用以下算法 uns
  • 预期类型为“System.Int64”,但实际值的类型为“System.String”

    有时 我们应用程序的用户会收到此信息无效强制转换异常预期类型为 System Int64 但实际值的类型为 System String 我们无法重现这种情况 并且它发生在identityDataGrid 模型的 DataGrid Id 字段
  • 如何识别每个簇内的序列?

    使用作为一部分的 biofam 数据集TraMineR library TraMineR data biofam lab lt c P L M LM C LC LMC D biofam seq lt seqdef biofam 10 25
  • 分页库使数据源无效不起作用

    最近我正在尝试这个 我有一个由数据源支持的作业列表 我正在使用分页库 并且作业列表中的每个项目都有一个保存按钮 并且该保存按钮将数据库中作业的状态从未保存更新为已保存 反之亦然 一旦更新 它就会使数据源失效 现在失效应该会导致当前页面立即重