目前,我们在 Room SQLite 中存储了一个数据结构,名为Todo
我们目前的工作流程如下
- 道回来了
DataSource.Factory<Integer, Todo>
- 使用
LivePagedListBuilder
将DataSource.Factory<Integer, Todo>
变成LiveData<PagedList<Todo>>
- 观察
LiveData<PagedList<Todo>>
,并使用submitList
将PagedList<Todo>
传递给PagedListAdapter<Todo, TodoAdapter.ViewHolder>
到目前为止,对于如此简单的用例来说很好。
但是,现在,我们有更复杂的 UI 要求。我们需要先将Todo
转换为TransformedTodo
,然后再submitList
PagedListAdapter
。
下面是我们的转换函数。
List<TransformedTodo> transform(Todo todo)
注意,可以将 1Todo
转换为 1 或多个TransformedTodo
。
我最初计划的工作流程是
- 道回来了
DataSource.Factory<Integer, Todo>
- 使用
DataSource.Factory.mapByPage
将DataSource.Factory<Integer, Todo>
转换为DataSource.Factory<Integer, TransformedTodo>
- 使用
LivePagedListBuilder
将DataSource.Factory<Integer, TransformedTodo>
变成LiveData<PagedList<TransformedTodo>>
- 观察
LiveData<PagedList<TransformedTodo>>
,并使用submitList
将PagedList<TransformedTodo>
传递给PagedListAdapter<TransformedTodo, TodoAdapter.ViewHolder>
棘手的部分是第 2 步。
如果转换函数返回其大小与输入List<Todo>
不同的输出List<TransformedTodo>
,则会抛出异常。
todosDataSourceFactory.mapByPage(new Function<List<Todo>, List<TransformedTodo>>() {
@Override
public List<TransformedTodo> apply(List<Todo> input) {
// Exception will be thrown if we are returning a List where its size is different from input.
}
});
抛出的异常看起来像
java.lang.IllegalStateException: 无效函数 com.yocto.wetodo.repository.TodoRepository$1@17b6f1b 更改返回 大小。不支持此操作。
原因如下
// androidx.paging.DataSource
static <A, B> List<B> convert(Function<List<A>, List<B>> function, List<A> source) {
List<B> dest = function.apply(source);
if (dest.size() != source.size()) {
throw new IllegalStateException("Invalid Function " + function
+ " changed return size. This is not supported.");
}
return dest;
}
似乎是分页库的限制。有没有办法将一个PagedList
转换为另一个不同大小的PagedList
?
参考链接 :
https://issuetracker.google.com/issues/142890117
如何使用列表大小不同于文件室数据库返回的列表大小的 AAC 分页库
TL;博士
我创建了一个库来允许分页库的数据源页面突变。
这里的问题是分页库mapByPage
被认为返回与输入项目相同数量的项目。为了能够返回与输入不同的项目数,需要一个自定义的变异函数。
在继续之前需要注意的另一件重要事情,尤其是在使用Room时,DataSource.Factory<Key, Value>
实际上最终会生成一个PositionalDataSource
.与ItemKeyedDataSource
和PageKeyedDataSource
不同,它要求生成的页面项遵循定义的页面大小。因此,即使我们创建一个类似mapByPage
的函数来允许其项目突变,接受不同的返回列表大小,在使用PositionalDataSource
时仍然会导致问题,因为它不允许此列表大小修改。
可以解决此问题的解决方案是将PositionalDataSource
包装在两种静止数据源类型中的另一种中,这些类型允许使用非固定页面大小,并使其表现得好像它实际上是一个PositionalDataSource
。
一旦我们有一个非固定的页面大小兼容"PositionalDataSource
",我们就可以添加类似mapByPage的突变函数。
我实际上已经创建了一个简单的可变数据源库,它正是这样做的。它将PositionalDataSource
包裹在一个行为相同的PageKeyedDataSource
中。然后,可以应用mutateByPage
功能,允许更改生成的项目,甚至更改列表大小或项目类型。此外,我还添加了对改变ItemKeyedDataSource
和PageKeyedDataSource
的支持。
请记住,此库仍可能包含错误,因此请随时报告任何问题或做出贡献。