airbnb / epoxy

Epoxy is an Android library for building complex screens in a RecyclerView
https://goo.gl/eIK82p
Apache License 2.0
8.52k stars 728 forks source link

EpoxyModel View Data Changes When Scrolling RecyclerView #1098

Open Piashsarker opened 3 years ago

Piashsarker commented 3 years ago

I am using epoxy for quick with different view types in the same recycler view. That's work like a charm!

one problem i am facing with view changes. I want to update my model view for a likeListener, seems like when i use condition in onBind the view is changing in other models/ items also. Below is my model class

@EpoxyModelClass(layout = R.layout.explore_item_user_post)
 public abstract class ItemUserPost extends DataBindingEpoxyModel {

@EpoxyAttribute
FeedResponse feedResponse;

@EpoxyAttribute(DoNotHash)
View.OnClickListener restaurantOnClick;

@EpoxyAttribute(DoNotHash)
View.OnClickListener followOnClick;

@EpoxyAttribute(DoNotHash)
View.OnClickListener likeOnClick;

@EpoxyAttribute(DoNotHash)
View.OnClickListener shareOnClick;

@EpoxyAttribute
boolean hideUserInfo;

@Override
public void bind(@NonNull DataBindingHolder holder) {
    super.bind(holder);
    ExploreItemUserPostBinding binding = (ExploreItemUserPostBinding) holder.getDataBinding();
    if (hideUserInfo) {
        binding.layoutUserInfo.setVisibility(View.GONE);
    }
    binding.btnFollow.setOnClickListener(followOnClick);
    binding.txtLike.setOnClickListener(likeOnClick);
    binding.txtShare.setOnClickListener(shareOnClick);
    binding.txtPost.setText(feedResponse.getDescription());
    binding.txtUserName.setText(String.format("%s %s", feedResponse.getCreatedBy().getFirstName(), feedResponse.getCreatedBy().getLastName()));
    binding.txtFollow.setText("0 Level 0 Followers");
    if (feedResponse.getImages().size() > 0) {
        BindingUtils.setImage(binding.imgPost, feedResponse.getImages().get(0), R.drawable.ic_frame_1, R.drawable.ic_frame_1);
    }
    BindingUtils.setImage(binding.imgUser, "", R.drawable.ic_placeholder_small, R.drawable.ic_placeholder_small);

    if (feedResponse.getRestaurantDetails() != null) {
        if (feedResponse.getRestaurantDetails().getDeliveryFee() == 0) {
            binding.txtRestaurantInfo.setText(App.getAppContext().getString(R.string.free_delivery));
        } else {
            binding.txtRestaurantInfo.setText(App.getAppContext().getString(R.string.delivery_fee_value, String.valueOf((int) feedResponse.getRestaurantDetails().getDeliveryFee())));
        }
        if (feedResponse.getRestaurantDetails().getReviewSummary() != null) {
            binding.rating.setRating((float) feedResponse.getRestaurantDetails().getReviewSummary().getAvgRating());
            binding.txtRating.setText(String.valueOf(feedResponse.getRestaurantDetails().getReviewSummary().getAvgRating()));
        }

        BindingUtils.setImage(binding.imgRestaurant, feedResponse.getRestaurantDetails().getLogo(), R.drawable.bg_circle_fafafa, R.drawable.bg_circle_fafafa);
        binding.txtRestaurantName.setText(feedResponse.getRestaurantDetails().getName());
    }

    if (feedResponse.getIsLike()) {
        binding.txtLike.setTextColor(BindingUtils.getColorResource(App.getAppContext(), R.color.colorPrimary));
        binding.txtLike.getCompoundDrawables()[0].setTint(BindingUtils.getColorResource(App.getAppContext(), R.color.colorPrimary));
    } else {
        binding.txtLike.setTextColor(BindingUtils.getColorResource(App.getAppContext(), R.color.like_button));
        binding.txtLike.getCompoundDrawables()[0].setTint(BindingUtils.getColorResource(App.getAppContext(), R.color.like_button));
    }

    binding.txtLikeCount.setText(App.getAppContext().getString(R.string.like_count, String.valueOf(feedResponse.getLikeCount())));
    binding.txtShare.setOnClickListener(shareOnClick);
    binding.txtLike.setOnClickListener(likeOnClick);
    binding.txtTime.setText(Utils.getTimeAgo(Utils.formattedDateFromStringToTimestampGMTIssue("yyyy-MM-dd HH:mm:ss.SSS", "", feedResponse.getCreatedAt())));
}

@Override
protected void setDataBindingVariables(ViewDataBinding binding) {

}

}

I am trying to listen onClick listener in my controller class. When i update a view after onClick and scroll down randomly views changes in my recyclerview.


 for (FeedResponse userPostInfo: userPostInfoArrayList) {
    new ItemUserPost_()
        .id(userPostInfo.getId())
        .hideUserInfo(false)
        .feedResponse(userPostInfo)
        .followOnClick((model, parentView, clickedView, position) -> {
            itemClickListener.onFoodiesFollowClick(model.feedResponse().getCreatedBy().getUsername());
        })
        .likeOnClick((model, parentView, clickedView, position) -> {
            itemClickListener.onFeedLikeClick(model.feedResponse());
            ExploreItemUserPostBinding binding = (ExploreItemUserPostBinding) parentView.getDataBinding();
            if (model.feedResponse().getIsLike()) {
                binding.txtLike.setTextColor(BindingUtils.getColorResource(App.getAppContext(), R.color.colorPrimary));
                binding.txtLike.getCompoundDrawables()[0].setTint(BindingUtils.getColorResource(App.getAppContext(), R.color.colorPrimary));
            } else {
                binding.txtLike.setTextColor(BindingUtils.getColorResource(App.getAppContext(), R.color.like_button));
                binding.txtLike.getCompoundDrawables()[0].setTint(BindingUtils.getColorResource(App.getAppContext(), R.color.like_button));
            }
            requestModelBuild();

        })
        .shareOnClick((model, parentView, clickedView, position) -> {
            itemClickListener.onShareClick(model.feedResponse());
        })
        .addIf(!isTrendingPostLoading && userPostInfoArrayList.size() > 0, this);
 }

**Please correct me what i am doing wrong here.** 

Thanks 
Piashsarker commented 3 years ago

See Video Sample

Piashsarker commented 3 years ago

@elihart Please have a look.

imherrera commented 3 years ago

enable debugLogging in your controller and watch your Logcat for strange behavior, also override onExceptionSwallowed and throw the exception, the models changing like that is probably because your ids are not stable, or maybe you have duplicated ids or because you are modifying a bounded model etc.

Also i would recommend that you implement only one clicklistener, and create an interface with a method that takes View as a parameter, then implement that interface in your activity or fragment and get the viewId so you can use a simple switch statement to know what item has been clicked in your model, that way you can move all the logic out of your controller