Android Recyclerview项目在刷新时混淆

Android Recyclerview项目在刷新时混淆,android,android-recyclerview,Android,Android Recyclerview,可能重复 我有一个Recyclerview,通过适配器和列表填充项目。问题是,在刷新时(通过SwipeRefreshLayout),倒计时计时器的数据混淆,错误的值显示在另一项上,如下图所示。项目1突出显示的计时器应显示“已过期”,但在刷新时,它将采用项目2的计时器值 这是我的适配器中的onBindViewHolder代码。我是否正确地实施了它 public class FeedAdapter extends RecyclerView.Adapter<FeedAdapter.FeedMo

可能重复

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

这是我的适配器中的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);
}

}
公共类FeedAdapter扩展了RecyclerView.Adapter{
私有列表feedModelList;
私有主监听;
私有上下文;
弦cPrice;
公共FeedAdapter(ListfeedModelList、上下文上下文、MainFeedListener bidFeedListener){
this.feedModelList=feedModelList;
this.mContext=上下文;
this.listener=bidfeedstener;
}
@非空
@凌驾
公共FeedModelViewHolder onCreateViewHolder(视图组父级,int-viewType){
视图v=LayoutInflater.from(parent.getContext()).flate(R.layout.item\u bid\u feed,parent,false);
返回新的FeedModelViewHolder(v);
}
@凌驾
BindViewHolder上的公共无效(@NonNull final-FeedModelViewHolder,final-int位置){
最终FeedModel FeedModel=feedModelList.get(位置);
((TextView)holder.bidView.findviewbyd(R.id.bid_title)).setText(feedModel.getTitle());
((TextView)holder.bidView.findviewbyd(R.id.start_price)).setText(feedModel.getCurrency()+“”+Convert(feedModel.getStartPrice());
((TextView)holder.bidView.findviewbyd(R.id.tags)).setText(feedModel.getTags());
((TextView)holder.bidView.findviewbyd(R.id.location)).setText(feedModel.getLocation());
新的倒计时(feedModel.getDaildate(),1000){
公共void onTick(长毫秒未完成){
((TextView)holder.bidView.findviewbyd(R.id.deadline)).setText(formatMillisSecondsToTime(millisUntilFinished));
feedModel.设定时间(毫秒);
}
公共无效onFinish(){
((TextView)holder.bidView.findviewbyd(R.id.deadline)).setText(“过期”);
}
}.start();
如果(!TextUtils.isEmpty(feedModel.getImageUrl())){
Glide.with(mContext.load)(feedModel.getImageUrl())
.缩略图(0.5f)
.crossFade()
.diskCacheStrategy(diskCacheStrategy.ALL)
.into((ImageView)holder.bidView.findviewbyd(R.id.bid_缩略图));
}
((LinearLayout)holder.bidView.findviewbyd(R.id.article\u card\u root)).setOnClickListener(新视图.OnClickListener()){
@凌驾
公共void onClick(视图){
onBidRowClicked(feedModel);
}
});
}
@凌驾
public int getItemCount(){
返回feedModelList.size();
}
公共静态类FeedModelViewHolder扩展了RecyclerView.ViewHolder{
私人观点;
公共FeedModelViewHolder(视图v){
超级(五);
bidView=v;
}
}
字符串转换(双d){
int i;
d+=0.005;
i=(int)(d*100);
双b=(双)(i/100);
返回b.toString();
}    
公共静态字符串格式毫秒到时间(长毫秒){
整数秒=(整数)(毫秒/1000)%60;
整数分钟=(整数)((毫秒/(1000*60))%60);
整数小时=(整数)(毫秒/(1000*60*60))//
//整数天=(整数)((毫秒/(1000*60*60))%24)//
返回twoDigitString(小时)+“:“+twoDigitString(分钟)+”:”
+两个数字串(秒);
}
私有静态字符串twoDigitString(长数字){
如果(数字==0){
返回“00”;
}
如果(数字/10==0){
返回“0”+数字;
}
返回字符串.valueOf(number);
}
}

我使用截取库填充列表,并通过构造函数将列表传递给适配器。这个问题很简单

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) {
    ...
 }
 }

这个问题很简单

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) {
    ...
 }
 }

您需要使用
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的
onBindViewHolder
在开始时被调用,并且每次都被重新绘制


但是,这种方法在创建视图时启动计时器,可能不会产生理想的结果。建议在
适配器之外的某个地方跟踪此时间,并只传递对它们的引用。

您需要使用
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的
onBindViewHolder
在开始时被调用,并且每次都被重新绘制


但是,这种方法在创建视图时启动计时器,可能不会产生理想的结果。建议在
适配器之外的某个地方跟踪此时间,并只传递对它们的引用。

请将您的holder类更改为:

 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;
        }
    }
打开