【问题标题】:How to use AAC paging library with list size different than list size returned by Room database如何使用列表大小与 Room 数据库返回的列表大小不同的 AAC 分页库
【发布时间】:2019-02-23 17:50:18
【问题描述】:

我正在尝试使用新的 Paging LibraryRoom 作为数据库,但我遇到了一个问题,数据库返回的 PagedList 不应该是发送到 UI 的同一个列表,我map 一些实体在向用户展示之前,在此map 操作期间,我更改了列表大小(添加项目),显然Paging Library 不支持这种操作,因为当我尝试运行应用程序时,我得到这个异常:

Caused by: java.lang.IllegalStateException: Invalid Function 'function_name' changed return size. This is not supported.

看分页库源码你看到这个方法:

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 添加动态项目时,是否有解决方法或需要处理的问题?

这就是我正在做的事情

@Query("SELECT * FROM table_name")
fun getItems(): DataSource.Factory<Int, Item>

本地来源

fun getItems(): DataSource.Factory<Int, Item> {
    return database.dao().getItems()
        .mapByPage { map(it) } // This map operation changes the list size
}

【问题讨论】:

  • 我遇到了像你这样的问题。如果您找到任何解决方案,请回答您的问题
  • 我为此在 Android 错误跟踪器上提交了一个问题。如果这对您有影响,请加注星标issuetracker.google.com/issues/142890117

标签: android android-room android-architecture-components android-paging


【解决方案1】:

我面临同样的问题,仍在寻找更好的解决方案。
就我而言,我必须在每个 用户从 API 加载之前显示 1 个部分,这是我的解决方法。

class UsersViewModel : ViewModel() {
    var items: LiveData<PagedList<RecyclerItem>>

    init {
        ...
        items = LivePagedListBuilder<Long, RecyclerItem>(
            sourceFactory.mapByPage { it -> mapUsersToRecyclerItem(it) }, config).build()
    }

    private fun mapUsersToRecyclerItem(users: MutableList<User>): List<RecyclerItem> {
        val numberOfSection = 1
        for (i in 0 until numberOfSection) {
            users.add(0, User()) // workaround, add empty user here
        }

        val newList = arrayListOf<RecyclerItem>()
        newList.add(SectionItem())
        for (i in numberOfSection until users.size) {
            val user = users[i]
            newList.add(UserItem(user.login, user.avatarUrl))
        }
        return newList
    }
}

我当前的用户类

data class User(
    @SerializedName("login")
    val login: String,
    @SerializedName("id")
    val id: Long = 0,
    @SerializedName("avatar_url")
    val avatarUrl: String
) {
    constructor() : this("", 0, "")
}

当然,要显示Section,我将有另一种方法而不将其添加到RecyclerView data list(例如仅使用位置),但在我的情况下,用户可以从列表中删除项目,因此使用位置可能难以处理

实际上,我回滚以使用旧负载更多方式(使用EndlessRecyclerViewScrollListener)但希望它有所帮助

【讨论】:

  • 您的输出newList 的大小是否与初始输入users 相同?我认为如果返回的输出 newList 与输入 users 的大小不同,则会引发异常?
【解决方案2】:

我想我找到了解决办法..

虽然这是一种解决方法,但它对我有用。

在我的例子中,我试图为这样的名称创建一个字母分区列表:

**A - HeaderItem**
Aaron - Item
Anny - Item
**B - HeaderItem**
Bob - Item
Bil
**C - HeaderItem**
....

ROOM 中的项目当然只是名称,当我尝试映射分页项目并添加节标题时,它会更改列表大小并且我得到相同的错误。

我所做的是,HeaderItem 对象像这样包装一个 Item:

首先,所有的Item都实现了ListItem接口

interface ListItem{
 const val HEADER = 0
 const val ITEM = 1
 fun getItemType() : Int
}

那么标题项是这样的

class HeaderItem(val headerTitle : String, val item : Item) : ListItem {
  @override
  fun getItemType() : Int {
    return ListItem.HEADER
  }
}

然后当我映射项目时,当添加一个 HeaderItem 时,它会在其中包含一个项目,这样映射的 PagedList 大小不会改变。现在我没有得到这个例外。

然而, 这会产生一些额外的工作,因为我必须显式设置 HeaderItem 装饰,并且还要在适配器中设置,当绑定标题项时,我必须注意内部 Item + 它的所有逻辑,例如单击侦听器等。

如果支持开箱即用的列表大小更改,我会很高兴。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-01
  • 2018-03-01
  • 2022-01-24
  • 2021-08-24
  • 1970-01-01
  • 2017-12-26
  • 1970-01-01
相关资源
最近更新 更多