Why RecyclerView.notifyItemChanged() will create a new ViewHolder and use both the old ViewHolder and new one?

后端 未结 6 536
半阙折子戏
半阙折子戏 2020-12-18 17:57

Recently I use RecyclerView and add a custom header view (another type of item view) and try to updated it when data has changed. Something strange happens. The adapter crea

相关标签:
6条回答
  • 2020-12-18 18:05

    Here are a few issues with your implementation:

    • getItemCount expects the count of all items in the recyclerview including the header so you should return mItemList.size() + 1

    • the position field in onBindViewHolder() refers to the position of an element in the whole recyclerview including the header. so to bind a non-header item you will do something like item = mItemList.get(position - 1) -- this won't fail because getItemViewType returns a number greater than 0 for TYPE_ITEMs

    By doing so, notifyItemChanged should behave as expected

    0 讨论(0)
  • 2020-12-18 18:20

    More cleaner solution (is not bug in animator, but this is a feature of layout manager):

    mRecyclerView.setLayoutManager(new GridLayoutManager(this, 5, LinearLayoutManager.VERTICAL, false){
            @Override
            public boolean supportsPredictiveItemAnimations() {
                return false;//super.supportsPredictiveItemAnimations();
            }
        });
    
    0 讨论(0)
  • 2020-12-18 18:23

    RecyclerView use both of ViewHolder for smooth animation from an old state to a new. This is default behaviour of RecyclerView.ItemAnimator.

    You can disable animation by passing an empty item animator to RecyclerView:

    listView.setItemAnimator(null);
    
    0 讨论(0)
  • 2020-12-18 18:23

    To avoid ViewHolder's recreating and without disabling smooth animation after call recyclerView.notifyItemChanged() you can set DefaultItemAnimator and override canReuseUpdatedViewHolder() method.

    Kotlin:

    val itemAnimator: DefaultItemAnimator = object : DefaultItemAnimator() {
          override fun canReuseUpdatedViewHolder(viewHolder: RecyclerView.ViewHolder): Boolean {
                return true
          }
    }
    recyclerView.itemAnimator = itemAnimator
    
    0 讨论(0)
  • 2020-12-18 18:24

    You can also use notifyItemChanged with a payload: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#notifyitemchanged. It will reuse the same ViewHolder instance: "if the item is already represented by a ViewHolder and it will be rebound to the same ViewHolder"

    0 讨论(0)
  • 2020-12-18 18:29
    ((SimpleItemAnimator) myRecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
    
    0 讨论(0)
提交回复
热议问题