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