java - PagedList 在使用 Room 的 Android 应用中不断增长但从未缩小

标签 java android kotlin

在我的 Android 应用程序中,我有一个非常基本的 RecyclerView 实现,它使用 Room 显示数据库中的条目。与 Paging library .

从数据库中获取条目的 Dao 方法:

@Query("SELECT * FROM entries")
abstract fun findAll(): DataSource.Factory<Int, Entry>

这就是在我的 ViewModel 中从返回的 DataSource.Factory 构造 LiveData 的方式:

private val config = PagedList.Config.Builder()
        .setEnablePlaceholders(false)
        .setInitialLoadSizeHint(512)
        .setPrefetchDistance(256)
        .setPageSize(256)
        .build()

val entries = LivePagedListBuilder(entryService.findAll(), config).build()
// (entryService here just calls through to the Dao)

我只是观察这个 LiveData 并将更新后的 PagedList 传递给我的 RecyclerView.Adapter

对应的RecyclerView.Adapter fragment :

private val differ = AsyncPagedListDiffer<Entry>(this, DIFF_CALLBACK)

fun submitList(list: PagedList<Entry>) {
    differ.submitList(list)
}

(我不使用 PagedListAdapter,因为稍后我需要在我的适配器中进行更细粒度的控制)

看似一切正常,但当我开始监控应用程序的内存使用情况时,我开始怀疑 PagedList 项目未正确处理。

我在 submitList() 中添加了以下 Callback:

list.addWeakCallback(differ.currentList?.snapshot(), object : PagedList.Callback() {
    override fun onChanged(position: Int, count: Int) {
        Log.d("_tag", "Position: $position | Changed: $count" +
                " | Size: ${list.size}")
    }

    override fun onInserted(position: Int, count: Int) {
        Log.d("_tag", "Position: $position | Inserted: $count" +
                " | Size: ${list.size}")
    }

    override fun onRemoved(position: Int, count: Int) {
        Log.d("_tag", "Position: $position | Removed: $count" +
                " | Size: ${list.size}")
    }
})

在此之后,我向数据库中插入了 5000 个条目,相应的日志条目如下:

D/_tag: Position: 0 | Inserted: 512 | Size: 512

很好,这是预期的输出。

但是当我开始在列表中向下滚动时,日志条目如下:

D/_tag: Position: 512 | Inserted: 256 | Size: 768

D/_tag: Position: 768 | Inserted: 256 | Size: 1024

D/_tag: Position: 1024 | Inserted: 256 | Size: 1280

D/_tag: Position: 1280 | Inserted: 256 | Size: 1536

然后日志就停在这里,不再有日志条目,无论我在这一点之后向下滚动多少。

我对这种行为的疑问:

  • 为什么从不调用 onRemoved()

    PagedList 是否是一个不断增长的列表并且项目保留在内存中?

    分页的目的不就是按需加载新条目并删除旧的(不可见的)条目吗?

  • 为什么日志在第 1536 个条目后停止,即使我滚动到该条目之前也是如此?

    奇怪的是,条目显示正确,即使一直滚动到列表底部也是如此。

如果有人能向我解释这种行为,我将不胜感激。

(也欢迎 Java 回答)

编辑:

整个适配器的代码:

class EntryListAdapter
        : RecyclerView.Adapter<EntryListAdapter.EntryViewHolder>() {

    private val differ = AsyncPagedListDiffer<Entry>(this, DIFF_CALLBACK)

    fun submitList(list: PagedList<Entry>) {
        differ.submitList(list)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
            EntryViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val entryItemView = inflater.inflate(R.layout.item_entry, parent, false)

        return EntryViewHolder(entryItemView)
    }

    override fun onBindViewHolder(holder: EntryViewHolder, position: Int) {
        differ.getItem(position)?.let { holder.bindTo(it) }
    }

    override fun getItemId(position: Int): Long {
        return differ.getItem(position)?.id ?: RecyclerView.NO_ID
    }

    override fun getItemCount(): Int {
        return differ.currentList?.size ?: 0
    }

    inner class EntryViewHolder(itemView: View) :
            RecyclerView.ViewHolder(itemView) {

        fun bindTo(entry: Entry) {
            itemView.textEntryTitle.text = entry.title
        }
    }

    companion object {
        private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Entry>() {
            override fun areItemsTheSame(entry1: Entry, entry2: Entry): Boolean {
                return entry1.id == entry2.id
            }

            override fun areContentsTheSame(entry1: Entry, entry2: Entry): Boolean
            {
                return entry1 == entry2
            }
        }
    }
}

EDIT2:

承载 RecyclerViewFragment 的布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/mainRecyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

最佳答案

Android 架构组件团队的 Chris Craik 刚刚确认 Reddit到目前为止,Paging 库不会丢弃分页数据(但它即将到来):

It is merged (1 and 2), but we haven't released it yet due to being extra-careful during the AndroidX switchover. Arch had to be careful to avoid causing regressions during an AndroidX migration (since those migrations are complex enough).

Now that AndroidX is stable, we can do the release, so we'll see about having it out soon.

关于java - PagedList 在使用 Room 的 Android 应用中不断增长但从未缩小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52676470/

相关文章:

android - 用浏览器代码替换一些特殊字符

kotlin - Kotlin中无限序列的递归定义

java - 使用 Java 逻辑三元运算符比较三个数字?

java - 从java中的动态Web应用程序发送邮件

Java 包不调整大小

kotlin - 如何结合JUnit4 @RunWith(Parameterized.class)和JUnit5 @ParameterizedTest

spring-boot - springboot 从 2.3.5.RELEASE 升级到 2.4.1-ClassNotFoundException : org. springframework.boot.context.properties.ConfigurationBeanFactoryMetadata

java - 从单个文本文件加载大量属性文件并插入 LinkedHashMap

android - Android中动态创建的UI组件的文本大小

android - 微调器的文本大小