Recyclerview的项目在刷新时混合在一起

时间:2018-07-17 07:04:37

标签: android android-recyclerview recycler-adapter

  

可能重复的RecyclerView Mixing Up Items

我有一个Recyclerview,我通过适配器和列表填充了项目。问题是,在刷新时(通过SwipeRefreshLayout),倒数计时器的数据混合在一起,并且错误的值显示在另一个项目上,如下图突出显示。项目1突出显示的计时器应该显示为“已过期”,但在刷新时它将使用项目2的计时器值

enter image description here

这是我的适配器中的onBindViewHolder代码。我执行正确吗?

public class FeedAdapter extends RecyclerView.Adapter<FeedAdapter.FeedModelViewHolder> {
private List<FeedModel> feedModelList;
private MainFeedListener listener;
private Context mContext;
String cPrice;

public FeedAdapter(List<FeedModel>feedModelList, Context context, MainFeedListener bidFeedListener) {
    this.feedModelList = feedModelList;
    this.mContext = context;
    this.listener = bidFeedListener;
}

@NonNull
@Override
public FeedModelViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_bid_feed, parent, false);
    return new FeedModelViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull final FeedModelViewHolder holder, final int position) {
    final FeedModel feedModel = feedModelList.get(position);
    ((TextView) holder.bidView.findViewById(R.id.bid_title)).setText(feedModel.getTitle());
    ((TextView) holder.bidView.findViewById(R.id.start_price)).setText(feedModel.getCurrency() +" "+Convert(feedModel.getStartPrice()));
    ((TextView) holder.bidView.findViewById(R.id.tags)).setText(feedModel.getTags());
    ((TextView) holder.bidView.findViewById(R.id.location)).setText(feedModel.getLocation());


    new CountDownTimer(feedModel.getDeadline(), 1000) {
        public void onTick(long millisUntilFinished) {
            ((TextView) holder.bidView.findViewById(R.id.deadline)).setText(formatMilliSecondsToTime( millisUntilFinished));
            feedModel.setTime(millisUntilFinished);
        }
        public void onFinish() {
            ((TextView) holder.bidView.findViewById(R.id.deadline)).setText("EXPIRED");
        }

    }.start();

    if (!TextUtils.isEmpty(feedModel.getImageUrl())) {
        Glide.with(mContext).load(feedModel.getImageUrl())
                .thumbnail(0.5f)
                .crossFade()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into((ImageView) holder.bidView.findViewById(R.id.bid_thumbnail));
     }
    ((LinearLayout) holder.bidView.findViewById(R.id.article_card_root)).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
           listener.onBidRowClicked(feedModel);
        }
    });
}


@Override
public int getItemCount() {
    return feedModelList.size();
}

public static class FeedModelViewHolder extends RecyclerView.ViewHolder {
    private View bidView;
    public FeedModelViewHolder(View v) {
        super(v);
        bidView = v;
    }
}


String Convert(Double d){
    int i;
    d +=0.005;
    i= (int) (d*100);
    Double b = (double) (i / 100);
    return b.toString();
}    

public static  String formatMilliSecondsToTime(long milliseconds) {

    int seconds = (int) (milliseconds / 1000) % 60;
    int minutes = (int) ((milliseconds / (1000 * 60)) % 60);
    int hours = (int) ((milliseconds / (1000 * 60 * 60))); //
  //  int days = (int) ((milliseconds / (1000 * 60 * 60)) % 24); //
    return twoDigitString(hours) + ":" + twoDigitString(minutes) + ":"
            + twoDigitString(seconds);
}

private static String twoDigitString(long number) {

    if (number == 0) {
        return "00";
    }

    if (number / 10 == 0) {
        return "0" + number;
    }

    return String.valueOf(number);
}

}

我使用Volley库填充列表,并通过构造函数将列表传递给适配器

3 个答案:

答案 0 :(得分:2)

请将您的持有人类别更改为此:

 public static class FeedModelViewHolder extends RecyclerView.ViewHolder {
        private View bidView;
        private TextView title;
        private TextView price;
        private TextView tags;
        private TextView location;
       public FeedModelViewHolder(View v) {
            super(v);
        title = v.findViewById(R.id.bid_title);
        price = v.findViewById(R.id.start_price)
        tags = v.findViewById(R.id.tags)
        location= v.findViewById(R.id.location);
        bidView = v;
        }
    }

在BindViewHolder上

@Override
public void onBindViewHolder(@NonNull final FeedModelViewHolder holder, final int position) {
    final FeedModel feedModel = feedModelList.get(position);
   holder,title.setText(feedModel.getTitle());
    holder.price.setText(feedModel.getCurrency() +" "+Convert(feedModel.getStartPrice()));
    holder.tags.setText(feedModel.getTags());
    holder.location.setText(feedModel.getLocation());
}

答案 1 :(得分:1)

这个问题很简单。

RecyclerView重用持有者,每次调用bind来更新其中的数据。

由于每次绑定任何数据时都会创建一个倒数计时器,所以最终会有多个计时器更新同一视图持有者。

最好的做法是将FeedViewHolder中的倒数计时器作为参考,在绑定数据(如果已启动)之前将其取消,然后将其重新安排为所需的持续时间。

public void onBindViewHolder(final FeedViewHolder holder, final int position) {
...
if (holder.timer != null) {
    holder.timer.cancel();
}
holder.timer = new CountDownTimer(expiryTime, 500) {
    ...
}.start();
 }

public static class FeedViewHolder extends RecyclerView.ViewHolder {
...
CountDownTimer timer;

public FeedViewHolder(View itemView) {
    ...
 }
 }

答案 2 :(得分:1)

您需要更多利用onCreateViewHolder。首先(不是真正的问题,而是可读性的提示),将视图绑定到字段

public class FeedModelViewHolder extends RecyclerView.ViewHolder {

    TextView bigTitle;
    TextView deadline;
    ...

    public FeedModelViewHolder(View v) {
        super(v);

        bitTitle =  = (TextView) v.findViewById(R.id.bid_title);
        deadline =  = (TextView) v.findViewById(R.id.deadline);
        ...

        new CountDownTimer(feedModel.getDeadline(), 1000) {
            public void onTick(long millisUntilFinished) {
                dealine.setText(formatMilliSecondsToTime( millisUntilFinished));
                feedModelList.get(getAdapterPosition()).setTime(millisUntilFinished);
            }
            public void onFinish() {
                dealine.setText("EXPIRED");
            }

        }.start();
    }
}

,然后在onCreateViewHolder中再次初始化您的计时器,因为它仅被调用一次。 onBindViewHolder在开始时以及每次重绘时都会被调用。

但是,此方法在创建视图时启动计时器,并且可能不会产生理想的结果。建议在Adapter之外的某个地方跟踪此时间,并仅将其传递给它们。