在RecyclerView中设置计数器 [英] Set counter inside RecyclerView
问题描述
我有倒数计时器,如下图所示:
现在这些计时器将开始在每个项目中递减计数,我尝试了多次以更改我的Adapter
计时器,但它不起作用,这是我的代码:
公共类AdapterItems扩展了RecyclerView.Adapter {
private ArrayList<TopCompetitions> mListItems = new ArrayList<>();
private ImageLoader mImageLoader;
private Context context;
private Handler handler;
/******************************************/
String current_date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d1 = null;
Date d2 = null;
long diff;
long diffSeconds;
long diffMinutes;
long diffHours;
long diffDays;
String reachableDate = "";
/******************************************/
private ScheduledFuture updateFuture;
public AdapterItems(Context context) {
this.context = context;
mImageLoader = AppController.getInstance().getImageLoader();
}
public void setmListItems(ArrayList<TopCompetitions> mListItems) {
this.mListItems = mListItems;
//update the adapter to reflect the new set of mListItems
notifyDataSetChanged();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.
from(parent.getContext()).
inflate(R.layout.custom_horizontal_row, parent, false);
return new ItemHolder(itemView);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final TopCompetitions currentItem = mListItems.get(position);
final ItemHolder itemHolder = (ItemHolder) holder;
/* start_date , name_com_ar , name_com_en,
question_en,answer_ar1,answer_ar2,answer_ar3
,answer_en1,answer_en2,answer_en3,right_answer;
*/
itemHolder.item_id.setText(currentItem.getPrize_id());
itemHolder.item_description.setText(currentItem.getName_com_ar());
itemHolder.start_date.setText(currentItem.getStart_date());
itemHolder.end_date.setText(currentItem.getEnd_date());
itemHolder.name_com_ar.setText(currentItem.getName_com_ar());
itemHolder.name_com_en.setText(currentItem.getName_com_en());
itemHolder.answer_en1.setText(currentItem.getAnswer_en1());
itemHolder.answer_en2.setText(currentItem.getAnswer_en2());
itemHolder.answer_en3.setText(currentItem.getAnswer_en3());
itemHolder.answer_ar1.setText(currentItem.getAnswer_ar1());
itemHolder.answer_ar2.setText(currentItem.getAnswer_ar2());
itemHolder.answer_ar3.setText(currentItem.getAnswer_ar3());
itemHolder.right_answer.setText(currentItem.getRight_answer());
itemHolder.question_en.setText(currentItem.getQuestion_en());
itemHolder.question_ar.setText(currentItem.getQuestion_ar());
itemHolder.desc_ar.setText(currentItem.getPrize_desc_ar());
itemHolder.desc_en.setText(currentItem.getPrize_desc_en());
String urlLogo = currentItem.getPrize_pic1();
loadImages(urlLogo, itemHolder);
setDefferinceTimer(itemHolder , currentItem.getEnd_date());
if (updateFuture == null) {
final Handler mainHandler = new Handler(Looper.getMainLooper());
updateFuture = Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
setDefferinceTimer(itemHolder , currentItem.getEnd_date());
notifyDataSetChanged();
mainHandler.post(new Runnable() {
@Override
public void run() {
notifyDataSetChanged();
}
});
}
}, 0, 1000, TimeUnit.MILLISECONDS);
}
/* new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
new CountDownTimer(20000, 1000) {
public void onTick(long millisUntilFinished) {
startCountDown(itemHolder, currentItem.getEnd_date() + " 00:00:00");
notifyDataSetChanged();
}
public void onFinish() {
//counterTextView.setText("done!");
}
}.start();
}
});
*/
}
public void setDefferinceTimer(final RecyclerView.ViewHolder holder , String itemEndDate){
final ItemHolder itemHolder = (ItemHolder) holder;
current_date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
// reachableDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(itemEndDate);
try {
d1 = format.parse(current_date);
d2 = format.parse(itemEndDate+" 00:00:00");
} catch (ParseException e) {
e.printStackTrace();
}
diff = d2.getTime() - d1.getTime();
diffSeconds = diff / 1000 % 60;
diffMinutes = diff / (60 * 1000) % 60;
diffHours = diff / (60 * 60 * 1000) % 24;
diffDays = diff / (24 * 60 * 60 * 1000);
itemHolder.days_tf.setText(""+diffDays);
itemHolder.hours_tf.setText(""+diffHours);
itemHolder.minutes_tf.setText(""+diffMinutes);
itemHolder.seconds_tf.setText(""+diffSeconds);
}
private void loadImages(String urlThumbnail, final RecyclerView.ViewHolder holder) {
final ItemHolder itemHolder = (ItemHolder) holder;
mImageLoader.get(urlThumbnail, new ImageLoader.ImageListener() {
@Override
public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
itemHolder.item_image.setImageBitmap(response.getBitmap());
//holder.salon_gender.setImageBitmap(response.getBitmap());
}
@Override
public void onErrorResponse(VolleyError error) {
}
});
}
@Override
public int getItemCount() {
return mListItems.size();
}
private class ItemHolder extends RecyclerView.ViewHolder {
public TextView item_id, item_description, end_date,
start_date, name_com_ar, name_com_en, question_ar,
question_en, answer_ar1, answer_ar2, answer_ar3, answer_en1,
answer_en2, answer_en3, right_answer , desc_ar , desc_en;
public TextView days_tf, hours_tf, minutes_tf, seconds_tf;
public CircleImageView item_image;
public ItemHolder(View itemView) {
super(itemView);
start_date = (TextView) itemView.findViewById(R.id.start_date);
end_date = (TextView) itemView.findViewById(R.id.end_date);
name_com_ar = (TextView) itemView.findViewById(R.id.name_com_ar);
name_com_en = (TextView) itemView.findViewById(R.id.name_com_en);
question_en = (TextView) itemView.findViewById(R.id.question_en);
question_ar = (TextView) itemView.findViewById(R.id.question_ar);
desc_ar = (TextView) itemView.findViewById(R.id.desc_ar);
desc_en = (TextView) itemView.findViewById(R.id.desc_en);
answer_ar1 = (TextView) itemView.findViewById(R.id.answer_ar1);
answer_ar2 = (TextView) itemView.findViewById(R.id.answer_ar2);
answer_ar3 = (TextView) itemView.findViewById(R.id.answer_ar3);
answer_en1 = (TextView) itemView.findViewById(R.id.answer_en1);
answer_en2 = (TextView) itemView.findViewById(R.id.answer_en2);
answer_en3 = (TextView) itemView.findViewById(R.id.answer_en3);
right_answer = (TextView) itemView.findViewById(R.id.right_answer);
item_id = (TextView) itemView.findViewById(R.id.item_id);
item_description = (TextView) itemView.findViewById(R.id.item_description);
item_image = (CircleImageView) itemView.findViewById(R.id.item_image);
days_tf = (TextView) itemView.findViewById(R.id.days_tf);
hours_tf = (TextView) itemView.findViewById(R.id.hours_tf);
minutes_tf = (TextView) itemView.findViewById(R.id.minutes_tf);
seconds_tf = (TextView) itemView.findViewById(R.id.seconds_tf);
}
}
编辑
这里有一个示例,可用于更新RecyclerView中的可见项目.我假设您为RecyclerView的布局使用 LinearLayoutManager ./p>
首先,从您的代码中删除CountDownTimer
.它的问题在于它使用主线程的循环程序来遍历消息(实际上,它使用当前线程",但是由于您在主线程中对其进行了初始化,因此当前线程现在是主线程)而且只能安排一个有限的时间间隔.
现在是新的部分.假设有一个片段启动了RecyclerView及其所有相关部分.假设这些是您片段中可用的字段:
private AdapterItems myAdapter;
private LinearLayoutManager layoutManager;
private ScheduledFuture updateFuture;
然后,在完成所有视图,适配器和其他初始化之后,将以下部分放入您的onCreateView(...)
中:
if (updateFuture == null) {
final Handler mainHandler = new Handler(Looper.getMainLooper());
updateFuture = Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
final int firstVisible = layoutManager.findFirstVisibleItemPosition();
final int lastVisible = layoutManager.findLastVisibleItemPosition();
mainHandler.post(new Runnable() {
@Override
public void run() {
myAdapter.notifyItemRangeChanged(firstVisible, lastVisible - firstVisible + 1);
}
});
}
}, 0, 1000, TimeUnit.MILLISECONDS);
}
这里有一些代码说明.我们创建了一个新的单线程 ScheduledExecutorService
,可用于以固定速率调度可运行对象( findFirstVisibleItemPosition()
和 notifyItemRangeChanged(...)
,它将通过自动调用onBindViewHolder(...)
来仅仅更新范围内给定项目的视图.
请注意用于在UI线程上调用notifyItemRangeChanged(...)
方法的mainHandler
,因为您无法从非UI线程更新UI(,而由ScheduledExecutorService
创建的非UI ).
当您不再需要通过调用cancel()
方法(例如,在片段的onDestroyView()
中)进行更新时,不要忘记取消ScheduledFuture.
if (updateFuture != null) {
updateFuture.cancel(true);
updateFuture = null;
}
原始
您有您的
Here's a sample that can be used to update the visible items in your RecyclerView. I assume you use LinearLayoutManager for your RecyclerView's layout. First of all, remove Now the new part. Assume there's your fragment that inits the RecyclerView and all its related parts. Let's say that these are the fields available in your fragment: Then put the following part into your Here's a little explanation of the code. We create a new single threaded Now the inner part. Every layout manager (except the base class Note the Don't forget to cancel your ScheduledFuture when you don't need the updates anymore by calling its
You have your 这篇关于在RecyclerView中设置计数器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!Items
类,我假设它包含列表项的所有数据(图像,文本等).您也应该将目标日期设置为此类,这样所有项目都可以具有不同的目标日期.如果您想稍后更新此日期,则必须在相应的Items
实例中进行更改,然后调用Edit
CountDownTimer
from your code. The problem with it is that it uses the main thread's looper to loop through the messages (actually it uses the "current thread" but since you initialize it in your main thread, current thread is main thread now) and it can only be scheduled for a finite interval.private AdapterItems myAdapter;
private LinearLayoutManager layoutManager;
private ScheduledFuture updateFuture;
onCreateView(...)
after you're done with all the view, adapter and other initializations:if (updateFuture == null) {
final Handler mainHandler = new Handler(Looper.getMainLooper());
updateFuture = Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
final int firstVisible = layoutManager.findFirstVisibleItemPosition();
final int lastVisible = layoutManager.findLastVisibleItemPosition();
mainHandler.post(new Runnable() {
@Override
public void run() {
myAdapter.notifyItemRangeChanged(firstVisible, lastVisible - firstVisible + 1);
}
});
}
}, 0, 1000, TimeUnit.MILLISECONDS);
}
ScheduledExecutorService
which can be used to schedule runnables at fixed rate (scheduleAtFixedRate(...)
). Every 1000 milliseconds from the call of this method, there's going to be a new execution.LayoutManager
) has two very important methods: findFirstVisibleItemPosition()
and findLastVisibleItemPosition()
. As the names show, these can be used to find the first and last visible items' position in the adapter. Then we use these informations to call the RecyclerView's adapter's (myAdapter
) notifyItemRangeChanged(...)
which will update only the given items' view in the range by calling onBindViewHolder(...)
automatically.mainHandler
which is used to call the notifyItemRangeChanged(...)
method on the UI thread as you cannot update the UI from a non-UI thread (and the one created by the ScheduledExecutorService
is non-UI).cancel()
method (e.g. in your fragment's onDestroyView()
).if (updateFuture != null) {
updateFuture.cancel(true);
updateFuture = null;
}
Original
Items
class which, I assume, contains all the data (images, text, etc.) for the list items. You should put the target date to this class as well, this way all your items can have different target dates. If you want to update this date later on, you'll have to change it in the appropriate Items
instance and call notifyItemChanged(position)
on your adapter.