滚动时 RecyclerView 中的多个倒数计时器闪烁 [英] Multiple count down timers in RecyclerView flickering when scrolled
问题描述
我已经为片段活动中的每个 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屋!