2

I have count down timer as image below :

enter image description here

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

    }



}
Ahmad Alkhatib
  • 1,230
  • 2
  • 14
  • 31
  • 1
    Please state what you want to do and what happens instead, also what you have tried already. – PhilMasteG Aug 23 '15 at 12:04
  • as u can see each item in that recyclerview has (image,text,counter) ,now these counters will start count down in each one to reachable date and that is not my problem counter works fine how to start counter in each one ,, i tried to get data from my API in my adapter and get reachable date to start count ,, as u can see . so ! is that enough ? – Ahmad Alkhatib Aug 23 '15 at 12:10

2 Answers2

2

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.

Gergely Kőrössy
  • 5,620
  • 3
  • 28
  • 44
  • yes i did all these things.. and works fine... but can u give me more explanation about notifyItemChanged()? – Ahmad Alkhatib Aug 23 '15 at 14:00
  • `notifyItemChanged(...)` notifies all observers that the **data** has changed on an item telling the RecyclerView that it's no longer valid and should rebind it calling `onBindViewHolder(...)` again. – Gergely Kőrössy Aug 23 '15 at 14:29
  • mmm for now u didn't tell me how to start counter dynamically in recycler items , anyway thanks man :) ... – Ahmad Alkhatib Aug 23 '15 at 15:48
  • 1
    You do start your CountDownTimer in `onBindViewHolder(...)`. If you want to update the view in each tick (i.e. every second), put your update logic into the `onTick(...)` method. Note that you should cancel the CountDownTimer with its `cancel()` method once the adapter's [`onViewRecycled(...)`](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#onViewRecycled%28VH%29) has been called by the RecyclerView to stop the timer. – Gergely Kőrössy Aug 23 '15 at 15:56
  • Thanks man u r right i already have the update method but it's out of the `onTick()` method , and when i put it inside on tick it works thanks ,,, but u know what ! i noticed that app got more slowly maybe cuz there are counter every where mmm do u have any ideas ! – Ahmad Alkhatib Aug 23 '15 at 18:36
  • Where exactly do you want to put it? – Gergely Kőrössy Aug 29 '15 at 13:00
  • Thanks man, i really appreciate what u wrote ,, but finally it works ,, but i don't know maybe that will be more load on memory , what i did is : find deffrince in times in each holder then just i added notifyDataSetChanged() with runnable in every second in onCreateView(); and every thing is work fine ,, – Ahmad Alkhatib Aug 29 '15 at 13:06
  • I don't understand what you did differently, but if it works, it's okay. – Gergely Kőrössy Aug 29 '15 at 13:12
  • @GergelyKőrössy Another solution cancels the countdowntimer before binding the data (if started) and reschedules to the desired duration. I wonder if the solution would be better for large numbers of items in a RecyclerView list compared to your solution. Can you comment/ See the solution by Lupsaa here: http://stackoverflow.com/questions/38890863/multiple-count-down-timers-in-recyclerview-flickering-when-scrolled. – AJW Oct 04 '16 at 02:47
1

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



}
Deepshikha Puri
  • 2,104
  • 22
  • 23