0

So I need one of two options but don't know where to start with either.

  • I have a list card views in a recyclerview. Each card view needs to have countdown timer implemented and able to run simultaneously. (Seems like the harder option) OR

  • Update the text in a card view based on if a specified time has elapsed or system time reaches a specified minute and hour.

alijandro
  • 11,627
  • 2
  • 58
  • 74
Adrian Le Roy Devezin
  • 672
  • 1
  • 13
  • 41

2 Answers2

2

To make the cards with different timers you will need threads. And the easiest way in Android is AsyncTask. So you create a bunch of AsyncTasks (probably you'd want an ArrayList to which you will add the AsyncTasks) and then with a cycle simply .execute() them.

Making an AsyncTask is very easy. You simply make a new class that is derived from AsyncTask and implement the doInBackground() method.

P.S. If you're developing for Android 3.0 and higher you will need to launch AsyncTasks this way:

.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

This will make them run simultaneously

Vendetta8247
  • 592
  • 1
  • 5
  • 30
  • Will this use a lot of battery? And keep running when user clicks home button? – Adrian Le Roy Devezin Jun 01 '15 at 00:48
  • @AdrianLeRoyDevezin it won't use a lot of battery simply because there are lots of threads running in each app. By default it will run if user clicks the home button. But it depends on what you want to do. If you want to make some kind of alert when the timer is done working that will be ok (though you might consider using a Service). If you want to return to the app screen and continue working it might get tricky. Android Activities go to the pause state and if your system will be running out of memory your app may get closed. So I wouldn't really count on that – Vendetta8247 Jun 01 '15 at 00:52
  • Seems it would be best to have the text change based on a specific time. Anyway to do that? – Adrian Le Roy Devezin Jun 01 '15 at 01:04
  • @AdrianLeRoyDevezin it is actually not much easier than the option I have told you (though I would recommend you to try what I have said to you as it is a widely used class) but I suppose than you would need a `Date` object and probably one more thread to keep checking the time. The other simply way is to create two `Date` objects - one for current time and one for the time you need - then count the difference between those two in milliseconds. Then you need to create a `Thread` and freeze it for the amount of milliseconds you have already counted – Vendetta8247 Jun 01 '15 at 01:10
2

UPDATE

As stated by others in other posts you have to know when to start and stop the timer because this is making you problems. I manged to make this work without canceling the recycler so here is my code.

public class ViewHolderContentCard extends RecyclerView.ViewHolder {

public TextView cardTv;
public CountdownUtils countdownUtils;

public ViewHolderContentCard(final View itemView) {
    super(itemView);

    cardTv = (TextView) itemView.findViewById(R.id.cardCountDownTvID);

    countdownUtils = new CountdownUtils(cardTv);
}}

 public class ContentRecyclerAdapterCard extends RecyclerView.Adapter<ViewHolderContentCard> {
private ArrayList<Content> mContentArrayList;

public ContentRecyclerAdapterCard(ArrayList<Content> contentArrayList) {

    this.mContentArrayList = contentArrayList;

}

@Override
public ViewHolderContentCard onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview_content, parent, false);

    ViewHolderContentCard viewHolderContentCard = new ViewHolderContentCard(view);
    return viewHolderContentCard;
}

@Override
public void onBindViewHolder(ViewHolderContentCard holder, int position) {

    holder.cardTextTv.setText(mContentArrayList.get(position).getmTitle());

    //update count down
    holder.countdownUtils.updateCountdownTv(mContentArrayList.get(position));
}

@Override
public int getItemCount() {
    return mContentArrayList.size();
}}

public class CountdownUtils {

private TextView mTextView;
private CountDownTimer mTimer;

public CountdownUtils(TextView textView) {
    mTextView = textView;
}

public void updateCountdownTv(Content content) {

    //cancel old timer to make sure one timer is updating one card
    cleanUpTimer();

    //get beginning and expiration period
    String dateFrom = content.getmDateFrom();
    String dateTo = content.getmDateTo();
    String timeFrom = content.getmTimeFrom();
    String timeTo = content.getmTimeTo();

    //process dates and update the countdown
    processCountDownAndUpdateUI(mTextView, dateFrom, dateTo, timeFrom, timeTo);
}

private void processCountDownAndUpdateUI(final TextView textView, String dateFrom, String dateTo, String timeFrom, String timeTo) {

    try {
        //format date and time
        Date beginningPeriod = getDateFromString(dateFrom, timeFrom);
        Date expirationPeriod = getDateFromString(dateTo, timeTo);

        //check beginning period with current time
        if (System.currentTimeMillis() < beginningPeriod.getTime()) {

            //we know that the is not available yet so display staring period - update the UI
            textView.setText("Starting from: " + dateFrom + " " + timeFrom);

        } else if (expirationPeriod.getTime() > System.currentTimeMillis()) {

            long availabilityPeriod = getAvailabilityPeriod(expirationPeriod);

            if (availabilityPeriod != 0) {
                //we have a valid avilability period so we need to start the countdown - update the UI
                startCountDownTimer(textView, availabilityPeriod);
            }
        }
    } catch (ParseException e) {
        e.printStackTrace();
    }
}

private void startCountDownTimer(final TextView textView, long availabilityPeriod) {

    //create countdown timer, count each second
    mTimer = new CountDownTimer(availabilityPeriod, 1000) {

        @Override
        public void onTick(long millisUntilFinished) {

            //format string will be displayed
            String timeSting = String.format("%d days %02d:%02d:%02d",
                    TimeUnit.MILLISECONDS.toDays(millisUntilFinished),
                    TimeUnit.MILLISECONDS.toHours(millisUntilFinished) - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(millisUntilFinished)),
                    TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millisUntilFinished)),
                    TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)));

            //display countdown
            textView.setText(timeSting);
        }

        @Override
        public void onFinish() {

            //expired inform the user
            textView.setText("Expired");
        }
    }.start();
}

private long getAvailabilityPeriod(Date periodFrom) {

    long availabilityPeriod = 0;

    //get expiration date as long
    long expPeriod = periodFrom.getTime();

    //check availability period
    if (expPeriod > System.currentTimeMillis()) {
        availabilityPeriod = expPeriod - System.currentTimeMillis();
    }

    return availabilityPeriod;
}

private Date getDateFromString(String date, String time) throws ParseException {

    //extract data as date and time
    Date formattedDate = new SimpleDateFormat("yyyy/MM/dd HH:mm").parse(date + " " + time);

    return formattedDate;
}

public void cleanUpTimer() {
    if (mTimer != null){
        mTimer.cancel();
    }    }}
Dharman
  • 30,962
  • 25
  • 85
  • 135
shadow-01
  • 201
  • 1
  • 4