RecyclerView blinking after notifyDatasetChanged()

前端 未结 18 1743
悲&欢浪女
悲&欢浪女 2020-12-07 16:20

I have a RecyclerView which loads some data from API, includes an image url and some data, and I use networkImageView to lazy load image.

@Override
public vo         


        
18条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-07 16:45

    In my case, neither any of above nor the answers from other stackoverflow questions having same problems worked.

    Well, I was using custom animation each time the item gets clicked, for which I was calling notifyItemChanged(int position, Object Payload) to pass payload to my CustomAnimator class.

    Notice, there are 2 onBindViewHolder(...) methods available in RecyclerView Adapter. onBindViewHolder(...) method having 3 parameters will always be called before onBindViewHolder(...) method having 2 parameters.

    Generally, we always override the onBindViewHolder(...) method having 2 parameters and the main root of problem was I was doing the same, as each time notifyItemChanged(...) gets called, our onBindViewHolder(...) method will be called, in which I was loading my image in ImageView using Picasso, and this was the reason it was loading again regardless of its from memory or from internet. Until loaded, it was showing me the placeholder image, which was the reason of blinking for 1 sec whenever I click on the itemview.

    Later, I also override another onBindViewHolder(...) method having 3 parameters. Here I check if the list of payloads is empty, then I return the super class implementation of this method, else if there are payloads, I am just setting the alpha value of the itemView of holder to 1.

    And yay I got the solution to my problem after wasting a one full day sadly!

    Here's my code for onBindViewHolder(...) methods:

    onBindViewHolder(...) with 2 params:

    @Override
    public void onBindViewHolder(@NonNull RecyclerAdapter.ViewHolder viewHolder, int position) {
                Movie movie = movies.get(position);
    
                Picasso.with(context)
                        .load(movie.getImageLink())
                        .into(viewHolder.itemView.posterImageView);
        }
    

    onBindViewHolder(...) with 3 params:

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List payloads) {
            if (payloads.isEmpty()) {
                super.onBindViewHolder(holder, position, payloads);
            } else {
                holder.itemView.setAlpha(1);
            }
        }
    
    
    

    Here's the code of method I was calling in onClickListener of viewHolder's itemView in onCreateViewHolder(...):

    private void onMovieClick(int position, Movie movie) {
            Bundle data = new Bundle();
            data.putParcelable("movie", movie);
    
            // This data(bundle) will be passed as payload for ItemHolderInfo in our animator class
            notifyItemChanged(position, data);
        }
    

    Note: You can get this position by calling getAdapterPosition() method of your viewHolder from onCreateViewHolder(...).

    I have also overridden getItemId(int position) method as follows:

    @Override
    public long getItemId(int position) {
        Movie movie = movies.get(position);
        return movie.getId();
    }
    

    and called setHasStableIds(true); on my adapter object in activity.

    Hope this helps if none of the answers above work!

    提交回复
    热议问题