首页 > 解决方案 > RecyclerView 更改图像不正确 onNotifyItemChanged

问题描述

我遇到了这个问题,使用 recyclerView,您可以查看下面的两个屏幕截图:

在此处输入图像描述

在此处输入图像描述

所以这是我的问题,当 onNotifyItemChange 运行时,其他信息被更改,不正确。现在这是我的适配器:

class TimelineAdapter(var timeline: TimelineDTO,
                      var toggleLikeClicked: OnRowClick,
                      var onCommentClicked: OnRowClick,
                      var onMediaClick: OnRowClick,
                      val onUserClicked: OnRowClick,

                      val reportPost: OnRowClick,
                      val editPost  : OnRowClick,
                      val deletePost: OnRowClick,

                      val contract: TimelineViewContract) : BaseAdapter<RecyclerView.ViewHolder>() {


    init {
        setHasStableIds(true)
    }

    private var currentItem: Int = 0

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        when (PostType.fromInt(viewType)) {
            PostType.BASIC -> {
                return PostViewHolder(parent.inflate(R.layout.row_post_default_item),
                                                    toggleLikeClicked, onCommentClicked, onMediaClick,
                                                    onUserClicked, reportPost,
                                                    editPost,
                                                    deletePost,
                                                    FirebaseAnalytics.getInstance(contract.returnContext()))
            }
            PostType.NEXT_TALKS -> {
                return PostNextTalksViewHolder(parent.inflate(R.layout.row_post_next_talks_item),
                                                    contract)
            }
            else -> {
                if(!BuildConfig.DEBUG) {
                    Crashlytics.log("Should not come here")
                }
                logE("adapter else!!")
                return PostViewHolder(parent.inflate(R.layout.row_post_default_item),
                                            toggleLikeClicked, onCommentClicked, onMediaClick,
                                            onUserClicked, reportPost,
                                            editPost,
                                            deletePost,
                                            FirebaseAnalytics.getInstance(contract.returnContext()))
            }
        }
    }

    override fun getItemCount(): Int {
        var count = timeline.posts.size
        if(hasValue(timeline.nextTalks.size)){
            count++
        }
        return count
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        currentItem = position
        val alignedPositon = getAlignedPosition(position)

        when (holder) {
            is PostViewHolder -> holder.bind(timeline.posts[alignedPositon])

            is PostNextTalksViewHolder -> {
                holder.bind(timeline.nextTalks)
            }
            is PostCarousselViewHolder -> {
                holder.bind(ArrayList<String>())
            }
        }
    }

    fun getPostAt(position: Int): PostDTO {
        val post: PostDTO
        val alignedPositon = getAlignedPosition(position)
        post = timeline.posts[alignedPositon]

        return post
    }

    override fun getItemId(position: Int): Long {
        val aligned = getAlignedPosition(position)

        return aligned.toLong()
    }

    private fun getAlignedPosition(position: Int): Int {
        var alignedPositon = position

        if (hasValue(timeline.nextTalks.size)){
            alignedPositon--
        }

        return alignedPositon
    }

    override fun getItemViewType(position: Int): Int {
        val hasPinned = timeline.posts.any { it.postType == PostType.PINNED.id }

        if(hasPinned) {
            if(position == 1 && timeline.nextTalks.any()){
                return PostType.NEXT_TALKS.id
            }
        }
        else {
            if(position == 0 && timeline.nextTalks.any()){
                return PostType.NEXT_TALKS.id
            }
        }

        return timeline.posts[getAlignedPosition(position)].postType

    }

    fun updateItemAt(postLocal: PostLocal, commentIndexPost: Int) {
        timeline.posts.removeAt(commentIndexPost)
        timeline.posts.add(commentIndexPost, PostDTO(postLocal))
        notifyItemChanged(commentIndexPost)
    }

    fun addItems(newPosts: TimelineDTO) {
        timeline.posts.addAll(newPosts.posts)
        timeline.nextTalks.addAll(newPosts.nextTalks)

        notifyItemRangeInserted(itemCount, newPosts.posts.size)
    }

    fun resetItems(nextPosts: TimelineDTO) {
        timeline.posts.clear()
        timeline.nextTalks.clear()

        timeline.posts.addAll(nextPosts.posts)
        timeline.nextTalks.addAll(nextPosts.nextTalks)

        notifyDataSetChanged()
    }

    fun removeAt(position: Int) {
        timeline.posts.removeAt(position)
        notifyItemRemoved(position)
        notifyItemRangeChanged(position, timeline.posts.size)
    }
}

标签: androidandroid-recyclerview

解决方案


使用notifyItemChanged()可能会触发不一定需要的“淡入淡出”效果(除非您在动画师中使用稳定的 ID 或终止更改动画)。

如果您知道项目中发生了什么变化,最好使用更新有效负载(参见此处的示例)来部分更新您的 ViewHolders 而不会触发完全重新绑定。

否则,如果列表相对较小并且您不知道发生了什么变化,您也可以使用DiffUtil“半自动”来帮助生成更改/更改有效负载列表。


推荐阅读