Как использовать библиотеку подкачки AAC с размером списка, отличным от размера списка, возвращаемого базой данных Room

Я пытаюсь использовать новый Paging Library а также Room в качестве базы данных, но я сталкиваюсь с проблемой, PagedList возвращенный базой данных не должен быть таким же списком, отправленным в пользовательский интерфейс, я 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 перед его использованием?

Это то что я делаю

DAO

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

LocalSource

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

1 ответ

Я сталкиваюсь с той же проблемой и все еще ищу лучшее решение.
В моем случае мне нужно отобразить 1 раздел перед загрузкой каждого пользователя из API, и вот мой обходной путь.

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 (например, использование только позиции), но в моем случае пользователь может удалить элемент из списка, поэтому использование позиции может быть затруднено

На самом деле, я откатился, чтобы использовать старый способ загрузки больше (с помощью https://www.google.com.vn/search?q=EndlessRecyclerViewScrollListener), но надеюсь, что это поможет

Думаю, я нашел решение..

Хотя это обходной путь, у меня это сработало.

В моем случае я пытался создать список с разделами по алфавиту для таких имен:

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

Элементы в ROOM - это, конечно, только имена, когда я пытаюсь сопоставить выгружаемые элементы и добавить заголовки разделов, это меняет размер списка, и я получаю ту же ошибку.

Я сделал следующее: объект HeaderItem обертывает элемент следующим образом:

Во-первых, все элементы реализуют интерфейс 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, а также в адаптере, при привязке элемента заголовка мне пришлось позаботиться о внутреннем элементе + всей его логике, такой как прослушиватели кликов и т.

Буду рад, если из коробки будет поддержка изменения размера списка.

Другие вопросы по тегам