滚动时 RecyclerView 中的多个倒数计时器闪烁 [英] Multiple count down timers in RecyclerView flickering when scrolled

查看:16
本文介绍了滚动时 RecyclerView 中的多个倒数计时器闪烁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经为片段活动中的每个 RecyclerView 项目实现了倒数计时器.倒数计时器显示到期的剩余时间.倒数计时器工作正常,但当向上滚动时它开始闪烁.搜索了很多,但没有得到很好的参考.有人可以帮我吗?

这是我的 RecyclerView 适配器

public class MyOfferAdapter extends RecyclerView.Adapter{私有最终上下文 mContext;私人最终 LayoutInflater mLayoutInflater;私有 ArrayListmItems = new ArrayList<>();私有 ImageLoader mImageLoader;私有字符串 imageURL;私人视图 mView;私人字符串 mUserEmail;公共 MyOfferAdapter(上下文上下文){mContext = 上下文;mLayoutInflater = LayoutInflater.from(context);VolleySingleton mVolley = VolleySingleton.getInstance(mContext);mImageLoader = mVolley.getImageLoader();}public void addItems(ArrayList items,String userEmail) {int count = mItems.size();mItems.addAll(items);mUserEmail = 用户邮箱;notifyItemRangeChanged(count, items.size());}@覆盖公共 FeedViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {mView = mLayoutInflater.inflate(R.layout.my_feed_item_layout, parent, false);返回新的 FeedViewHolder(mView);}@覆盖公共无效onBindViewHolder(最终FeedViewHolder持有人,最终int位置){holder.desc.setText(mItems.get(position).getDescription());//按标题替换holder.scratchDes.setText(mItems.get(position).getScratchDescription());长定时器 = mItems.get(position).getTimerExpiryTimeStamp();今天的日期 = new Date();final long currentTime = today.getTime();长到期时间 = 计时器 - 当前时间;新 CountDownTimer(expiryTime, 500) {公共无效onTick(长millisUntilFinished){长秒数 = millisUntilFinished/1000;长分钟 = 秒/60;长时间 = 分钟/60;长天 = 小时/24;字符串时间 = days+" "+"days" +" :" +hours % 24 + ":" + 分钟 % 60 + ":" + seconds % 60;holder.timerValueTimeStamp.setText(time);}公共无效 onFinish() {holder.timerValueTimeStamp.setText("时间到了!");}}.开始();}@覆盖公共 int getItemCount() {返回 mItems.size();}公共静态类 FeedViewHolder 扩展 RecyclerView.ViewHolder {文本视图描述;TextView scratchDes;TextView timerValueTimeStamp;ImageView feedImage;CardView mCv;公共 FeedViewHolder(查看 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);}}

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

<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"机器人:layout_gravity="中心"应用程序:cardUseCompatPadding="true"应用程序:cardElevation="4dp"机器人:海拔=6dp"><相对布局android:layout_width="match_parent"android:layout_height="match_parent"><图像视图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"/><文本视图android:id="@+id/tv_scratch_description"style="@style/ListItemText"android:layout_width="match_parent"android:layout_height="wrap_content"机器人:重力=中心"机器人:文本=卡苏尔鞋"android:fontFamily="sans-serif-light"android:padding="10dp"/><文本视图android:id="@+id/tv_timer_value_time_stamp"style="@style/CardTitle"android:layout_width="wrap_content"android:layout_height="wrap_content"机器人:layout_centerInParent =真"/><文本视图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"机器人:填充=10dp"/></RelativeLayout></android.support.v7.widget.CardView>

这是我的 RecyclerView 的屏幕截图

解决方案

这个问题很简单.

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

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

这里最好的方法是将 FeedViewHolder 中的 CountDownTimer 作为参考,在绑定数据(如果已启动)之前取消它并重新安排到所需的持续时间.

<块引用>

public void onBindViewHolder(final FeedViewHolder holder, final int position) {...if (holder.timer != null) {持有人.计时器.取消();}holder.timer = 新的 CountDownTimer(expiryTime, 500) {...}.开始();}公共静态类 FeedViewHolder 扩展 RecyclerView.ViewHolder {...CountDownTimer 计时器;公共 FeedViewHolder(查看 itemView){...}}

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

I have implemented count down timer for each item of RecyclerView which is in a fragment activity. The count down timer shows the time remaining for expiry. The count down timer is working fine but when scrolled up it starts flickering. Searched a lot but did not got the good reference. Can any one help me?

This is my RecyclerView adapter

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);

    }

}

And this is my xml file used in adapter

<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>

And this is screen shot of my RecyclerView

解决方案

This problem is simple.

RecyclerView reuses the holders, calling bind each time to update the data in them.

Since you create a CountDownTimer each time any data is bound, you will end up with multiple timers updating the same ViewHolder.

The best thing here would be to move the CountDownTimer in the FeedViewHolder as a reference, cancel it before binding the data (if started) and rescheduling to the desired duration.

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

This way you will cancel any current timer instance for that ViewHolder prior to starting another timer.

这篇关于滚动时 RecyclerView 中的多个倒数计时器闪烁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆