滚动时,RecyclerView中的多个倒计时器会闪烁

Has*_*ikh 12 android countdowntimer android-recyclerview

我已经为每个RecyclerView项目实现了倒计时器,这是一个片段活动.倒计时器显示到期时间.倒计时器工作正常,但向上滚动时会开始闪烁.搜索了很多,但没有得到很好的参考.谁能帮我?

这是我的RecyclerView适配器

public class MyOfferAdapter extends RecyclerView.Adapter<MyOfferAdapter.FeedViewHolder>{
private final Context mContext;
private final LayoutInflater mLayoutInflater;
private ArrayList<Transactions> mItems = new ArrayList<>();
private ImageLoader mImageLoader;
private String imageURL;
private View mView;
private String mUserEmail;

public MyOfferAdapter(Context context) {
    mContext = context;
    mLayoutInflater = LayoutInflater.from(context);
    VolleySingleton mVolley = VolleySingleton.getInstance(mContext);
    mImageLoader = mVolley.getImageLoader();
}


public void addItems(ArrayList<Transactions> items,String userEmail) {
    int count = mItems.size();
    mItems.addAll(items);
    mUserEmail = userEmail;
    notifyItemRangeChanged(count, items.size());
}


@Override
public FeedViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    mView = mLayoutInflater.inflate(R.layout.my_feed_item_layout, parent, false);
    return new FeedViewHolder(mView);
}

@Override
public void onBindViewHolder(final FeedViewHolder holder, final int position) {
    holder.desc.setText(mItems.get(position).getDescription());//replace by title
    holder.scratchDes.setText(mItems.get(position).getScratchDescription());

    long timer = mItems.get(position).getTimerExpiryTimeStamp();
    Date today = new Date();
    final long currentTime = today.getTime();
    long expiryTime = timer - currentTime;


    new CountDownTimer(expiryTime, 500) {
        public void onTick(long millisUntilFinished) {
            long seconds = millisUntilFinished / 1000;
            long minutes = seconds / 60;
            long hours = minutes / 60;
            long days = hours / 24;
            String time = days+" "+"days" +" :" +hours % 24 + ":" + minutes % 60 + ":" + seconds % 60;
            holder.timerValueTimeStamp.setText(time);
        }

        public void onFinish() {
            holder.timerValueTimeStamp.setText("Time up!");
        }
    }.start();

}

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

public static class FeedViewHolder extends RecyclerView.ViewHolder {
    TextView desc;
    TextView scratchDes;
    TextView timerValueTimeStamp;
    ImageView feedImage;
    CardView mCv;

    public FeedViewHolder(View itemView) {
        super(itemView);
        mCv = (CardView) itemView.findViewById(R.id.cv_fil);
        desc = (TextView) itemView.findViewById(R.id.desc_tv_fil);
        feedImage = (ImageView) itemView.findViewById(R.id.feed_iv_fil);
        scratchDes = (TextView) itemView.findViewById(R.id.tv_scratch_description);
        timerValueTimeStamp = (TextView) itemView.findViewById(R.id.tv_timer_value_time_stamp);

    }

}
Run Code Online (Sandbox Code Playgroud)

这是我在适配器中使用的xml文件

<LinearLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<android.support.v7.widget.CardView     xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cv_fil"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="@dimen/card_margin"
    android:layout_gravity="center"
    app:cardUseCompatPadding="true"
    app:cardElevation="4dp"
    android:elevation="6dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:id="@+id/feed_iv_fil"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:layout_alignParentTop="true"
            android:scaleType="fitXY"
            android:tint="@color/grey_tint_color" />

        <TextView
            android:id="@+id/tv_scratch_description"
            style="@style/ListItemText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="casul shoes"
            android:fontFamily="sans-serif-light"
            android:padding="10dp" />


        <TextView
            android:id="@+id/tv_timer_value_time_stamp"
            style="@style/CardTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            />

        <TextView
            android:id="@+id/desc_tv_fil"
            style="@style/VendorNameText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/feed_iv_fil"
            android:textColor="#3f3e3f"
            android:padding="10dp"
            />

    </RelativeLayout>


</android.support.v7.widget.CardView>
Run Code Online (Sandbox Code Playgroud)

这是我的RecyclerView的屏幕截图 在此输入图像描述

And*_*psa 27

这个问题很简单.

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

由于CountDownTimer每次绑定任何数据时都会创建,因此最终会有多个计时器更新相同的数据ViewHolder.

这里的最好的事情是移动CountDownTimerFeedViewHolder为参考,结合数据(如果启动),并重新安排到所需的时间前将其取消.

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) {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,您将ViewHolder在启动另一个计时器之前取消任何当前计时器实例.

  • @Lupsaa我注意到其他解决方案使用 Handler 和 Runnable 方法和对象来更新主线程之外的新线程。我想知道与您的解决方案相比,这些解决方案对于 RecyclerView 列表中的大量项目是否会更好。你能发表评论吗?请参阅 Gergely Kőrössy 的答案:http://stackoverflow.com/questions/32166375/set-counter-inside-recyclerview 和 H Raval 的答案:http://stackoverflow.com/questions/35860780/recyclerview-with-multiple -倒计时器导致闪烁。 (2认同)
  • @AJW由于持有人正在回收,列表中的大量物品都没有关系。您可以拥有10.000个项目的列表,如果一次仅可见10个项目,则可能会有约15个持有者实例被重用。在这里,我只是通过解释他为什么遇到闪烁的问题来提供答案。我敢肯定有多种方法,但我认为使用线程/处理程序是过大的。由于绑定视图时将启动每个计时器,因此该解决方案将不会同时更新所有者。 (2认同)

Far*_*deh 5

正如 Andrei Lupsa 所说,您应该在 ViewHolder 中保留 CountDownTimer 引用,如果您不想在滚动 (onBindViewHolder) 时重置计时器,则应检查 CountDownTimer 引用是否在 onBindViewHolder 中为 null :

public void onBindViewHolder(final FeedViewHolder holder, final int position) {

      ...

      if (holder.timer == null) {
          holder.timer = new CountDownTimer(expiryTime, 500) {

          ...

          }.start();   
      }
}


public static class FeedViewHolder extends RecyclerView.ViewHolder {

       ...

       CountDownTimer timer;

       public FeedViewHolder(View itemView) {

          .... 
  }
}
Run Code Online (Sandbox Code Playgroud)