Saturday, 3 December 2016

Something wrong happens with RecyclerView

New items are added to RecyclerView each time when Adapter have created. In photo I showed a process where darken dish images appear, though I managed image darking with a condition if(holder.mDish.getPicurl()!=null), but it doest work.
If I go into darken dish image details and go back to list, there will by three darken images. Is it problem with RecyclerView or it is my fault?
enter image description here
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    holder.mDish = DISHES.get(position);
    final int id = holder.mDish.getId();

   if(holder.mDish.getPicurl()!=null) {
        Picasso.with(mContext)
                .load(holder.mDish.getPicurl())
                .fit()
                .transform(new RoundedTransformation(20, 0))
                .into(holder.mIvBackground);
        holder.mIvBackground.setColorFilter(Color.parseColor("#aaaaaa"), PorterDuff.Mode.MULTIPLY);
    } else {
        holder.mIvBackground.setImageResource(R.drawable.vector_drawable_dish);
    }


    holder.mTvName.setText(holder.mDish.getName());
    //holder.mTvDescription.setText(holder.mDish.getDescription());
    holder.mTvPrice.setText("T " + String.valueOf(holder.mDish.getPrice()));
    holder.mBtnAdd.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(mListener!=null){
                mListener.onAddToBasketInteraction(id);
            }
        }
    });
    holder.mView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mListener.onStartDetailActivity(id);
        }
    });
}


public void addDishes(List<Dish> dishes){
    DISHES.clear();
    DISHES.addAll(dishes);
    notifyDataSetChanged();
}


public class ViewHolder extends RecyclerView.ViewHolder {

    public Dish mDish;
    public final View mView;
    public final ImageView mIvBackground;
    public final TextView mTvName;
    //public final TextView mTvDescription;
    public final TextView mTvPrice;
    public final ImageButton mBtnAdd;

    public ViewHolder(View itemView) {
        super(itemView);
        mView = itemView;
        mIvBackground = (ImageView) itemView.findViewById(R.id.dishBackground);
        mTvName = (TextView) itemView.findViewById(R.id.name);
        //mTvDescription = (TextView) itemView.findViewById(R.id.description);
        mTvPrice = (TextView) itemView.findViewById(R.id.price);
        mBtnAdd = (ImageButton) itemView.findViewById(R.id.btnAdd);
    }
}
xml of item:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:orientation="horizontal"
    android:padding="2dp">

    <ImageView
        android:id="@+id/dishBackground"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Плов узбекский"
        android:textColor="@color/colorAccent2"
        android:layout_marginLeft="5dp"
        android:layout_marginBottom="5dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:textSize="14sp" />



    <TextView
        android:id="@+id/price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="5dp"
        android:layout_marginTop="5dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:text="T 3000"
        android:textColor="@android:color/holo_orange_light" />

    <ImageButton
        android:id="@+id/btnAdd"
        android:layout_width="30dp"

--------------------------------------------------------------------------------------------------------------------------

1 Answer


You don't undo view changes in conditional statement

The culprit is this piece of code:
if(holder.mDish.getPicurl()!=null) {
    Picasso.with(mContext)
            .load(holder.mDish.getPicurl())
            .fit()
            .transform(new RoundedTransformation(20, 0))
            .into(holder.mIvBackground);
    holder.mIvBackground.setColorFilter(Color.parseColor("#aaaaaa"), PorterDuff.Mode.MULTIPLY);
} else {
    holder.mIvBackground.setImageResource(R.drawable.vector_drawable_dish);
}
The way RecyclerView works is it reuses the same views with a different data (hence recycler), so the onBindViewHolder method may be called multiple times for each position, but the ViewHoldermight have been already created and previously bound to a different piece of data. That way some changes applied to the view inside the onBindViewHolder method might persist through bind calls to different pieces of data.
In your case, the following call:
holder.mIvBackground.setColorFilter(Color.parseColor("#aaaaaa"), PorterDuff.Mode.MULTIPLY);
alters the view with the color filter within one call to onBindViewHolder. Then, when another piece of data is bound to the same ViewHolder, the condition holder.mDish.getPicurl()!=null might be false, but the effect still persists, because there is no removal of this color filter in the else branch of your statement.

Fix

You need to explicitly set and unset any changes to a single view in your RecyclerView for every separate condition you wish to implement:
if(holder.mDish.getPicurl()!=null) {
    holder.mIvBackground.setColorFilter(Color.parseColor("#aaaaaa"), PorterDuff.Mode.MULTIPLY);
} else {
    holder.mIvBackground.setColorFilter(null); // removes color filter
}
You don't see any problems with your mIvBackground because you set a different one in each branch of your if-else statement, so no unwanted state persists.







No comments:

Post a Comment