问题
I have count down timer as image below :
now these timers will start count down in each item, i tried many times to change this from my Adapter
and it's not work,here is my code:
Edit :
public class AdapterItems extends 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);
}
}
回答1:
Edit
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 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.
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:
private AdapterItems myAdapter;
private LinearLayoutManager layoutManager;
private ScheduledFuture updateFuture;
Then put the following part into your 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);
}
Here's a little explanation of the code. We create a new single threaded 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.
Now the inner part. Every layout manager (except the base class 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.
Note the 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).
Don't forget to cancel your ScheduledFuture when you don't need the updates anymore by calling its cancel()
method (e.g. in your fragment's onDestroyView()
).
if (updateFuture != null) {
updateFuture.cancel(true);
updateFuture = null;
}
Original
You have your 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.
回答2:
Here you can find the source code of Countdown Timer in Recycler Listview here
Adapter.java
import android.os.CountDownTimer;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
public class Adapter extends RecyclerView.Adapter{
private ArrayList al_data;
public class MyViewHolder extends RecyclerView.ViewHolder{
public TextView tv_timer;
CountDownTimer timer;
public MyViewHolder (View view){
super(view);
tv_timer = (TextView)view.findViewById(R.id.tv_timer);
}
}
public Adapter(ArrayList al_data) {
this.al_data = al_data;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_layout,parent,false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
holder.tv_timer.setText(al_data.get(position));
if (holder.timer != null) {
holder.timer.cancel();
}
long timer = Long.parseLong(al_data.get(position));
timer = timer*1000;
holder.timer = new CountDownTimer(timer, 1000) {
public void onTick(long millisUntilFinished) {
holder.tv_timer.setText("" + millisUntilFinished/1000 + " Sec");
}
public void onFinish() {
holder.tv_timer.setText("00:00:00");
}
}.start();
}
@Override
public int getItemCount() {
return al_data.size();
}
}
来源:https://stackoverflow.com/questions/32166375/set-counter-inside-recyclerview