首页 > 解决方案 > Android Paging library 3 在滚动时插入新项目时抛出异常

问题描述

我正在使用 Paging library 3 开发一个 Android 聊天应用程序androidx.paging:paging-runtime-ktx:3.0.0-alpha12

分页库从 Room 数据库中检索聊天消息。

当我在 Room 数据库中的 ChatMessage 表中插入新的聊天消息时,在滚动聊天消息的回收器视图时,它会根据下面的 GIF 引发异常。发送按钮只是将一个新项目插入到 ChatMessage 表中。

在此处输入图像描述

这是错误日志。

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.beeswork.balance, PID: 24171
    java.lang.UnsupportedOperationException: Stable ids are unsupported on PagingDataAdapter.
        at androidx.paging.PagingDataAdapter.setHasStableIds(PagingDataAdapter.kt:127)
        at com.beeswork.balance.ui.chat.ChatFragment.setupChatRecyclerView(ChatFragment.kt:71)
        at com.beeswork.balance.ui.chat.ChatFragment.access$setupChatRecyclerView(ChatFragment.kt:24)
        at com.beeswork.balance.ui.chat.ChatFragment$bindUI$1.invokeSuspend(ChatFragment.kt:58)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
Disconnected from the target VM, address: 'localhost', transport: 'socket'

这是在聊天片段中设置聊天回收器视图的代码

private fun setupChatRecyclerView() {
    chatPagingAdapter = ChatPagingAdapter()
    rvChat.adapter = chatPagingAdapter
    val layoutManager = LinearLayoutManager(this@ChatFragment.context)
    layoutManager.orientation = LinearLayoutManager.VERTICAL
    layoutManager.reverseLayout = true
    rvChat.layoutManager = layoutManager
    lifecycleScope.launch {
        viewModel.chatMessages.collectLatest {
            chatPagingAdapter.submitData(it)
        }
    }
}

这是 ChatViewModel 中的 chatMessages

val chatMessages = Pager(
    PagingConfig(
        pageSize = 30,
        enablePlaceholders = false,
        maxSize = 150
    )
) {
    balanceRepository.getChatMessages(chatId)
}.flow.cachedIn(viewModelScope)

这是 ChatDAO 中的查询

@Query("select * from chatMessage where chatId = :chatId order by case when id is null then 0 else 1 end, id desc, messageId desc")
fun getChatMessages(chatId: Long): PagingSource<Int, ChatMessage>

这是 ChatPagingAdapter 扩展了 PagingDataAdapter

class ChatPagingAdapter : PagingDataAdapter<ChatMessage, ChatPagingAdapter.MessageViewHolder>(
    diffCallback
) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder {
        return when (viewType) {
            ChatMessage.Status.RECEIVED.ordinal -> MessageViewHolder(parent.inflate(R.layout.item_chat_message_received))
            ChatMessage.Status.SENT.ordinal -> MessageViewHolder(parent.inflate(R.layout.item_chat_message_sent))
            else -> MessageViewHolder(parent.inflate(R.layout.item_chat_message_received))
        }
    }

    override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {
        getItem(position)?.let {
            when (holder.itemViewType) {
                ChatMessage.Status.RECEIVED.ordinal -> holder.bindMessageReceived(it)
                ChatMessage.Status.SENT.ordinal -> holder.bindMessageSent(it)
            }
        }
    }

    override fun getItemViewType(position: Int): Int {
        return getItem(position)?.let {
            return if (it.status == ChatMessage.Status.RECEIVED) ChatMessage.Status.RECEIVED.ordinal else ChatMessage.Status.SENT.ordinal
        } ?: kotlin.run {
            return ChatMessage.Status.RECEIVED.ordinal
        }
    }

    companion object {
        private val diffCallback = object : DiffUtil.ItemCallback<ChatMessage>() {
            override fun areItemsTheSame(oldItem: ChatMessage, newItem: ChatMessage): Boolean =
                oldItem.id == newItem.id

            override fun areContentsTheSame(oldItem: ChatMessage, newItem: ChatMessage): Boolean =
                oldItem == newItem
        }
    }

    class MessageViewHolder(
        itemView: View
    ) : RecyclerView.ViewHolder(itemView) {
        fun bind {...}
    }
   }

这里有问题

  1. 我可以在向聊天消息表插入新项目时保持滚动吗?
  2. 如果不可能,那么我该如何解决异常呢?

标签: android-recyclerviewandroid-roomvertical-scrollingandroid-paging-library

解决方案


推荐阅读