1

I am having trouble implementing async task with countdown timer class. I have a countdown timer that updates the ui;however, if I go to other applications the time starts from the beginning, so I need to use async task. Only problem is that I don't know how to incorporate async task with my countdown timer class, would anyone know how to solve this?

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_count_down);


        countDown = new CountDownTime(actualTimeFiniliazedInMilliSeconds, timeInterval);
       countDown.start();

        new UpdateCountDownTime().execute();



    }

    public class CountDownTime extends CountDownTimer {
        /**
         * @param millisInFuture    The number of millis in the future from the call
         *                          to {@link #start()} until the countdown is done and {@link #onFinish()}
         *                          is called.
         * @param countDownInterval The interval along the way to receive
         *                          {@link #onTick(long)} callbacks.
         */
        public CountDownTime(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
        }

        @Override
        public void onTick(long millisUntilFinished) {

            long millis = millisUntilFinished;
           hms = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
                    TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
                    TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));

            // currentCountDownTime.setText(currentCountDownTime.getText() + String.valueOf(millisUntilFinished));
            timeTextView.setText(hms);
        }

        @Override
        public void onFinish() {
           Intent goBack = new Intent(CountDownAct.this, ListOfAlarms.class);
            startActivity(goBack);
            finish();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        timeTextView.setText(hms);
    }

        private class UpdateCountDownTime extends AsyncTask<Void, Void, Void> {
            @Override
            protected Void doInBackground(Void... params) {
                countDown = new CountDownTime(actualTimeFiniliazedInMilliSeconds, timeInterval);
                countDown.start();
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                ((TextView) findViewById(R.id.timeTextView)).setText(hms);
            }

     }
leonardo
  • 93
  • 2
  • 10
  • 1
    You probably want to use it with a service if you want to use it when the app isn't in the foreground – codeMagic Jul 20 '15 at 00:41
  • ok but what type of service? Also, what is the async task used for than? – leonardo Jul 20 '15 at 00:58
  • use TimerTask or Runnable postDelay like [this](http://www.mopri.de/2010/timertask-bad-do-it-the-android-way-use-a-handler/) – calvinfly Jul 20 '15 at 01:15
  • Maybe this one http://stackoverflow.com/questions/22496863/how-to-run-countdowntimer-in-a-service-in-android I didn't really look at the code but sounds like the same thing you are trying to achieve. AsyncTasks are great for short lived operations to do some quick work on the background then update the UI. But if you want something to run when the app isn't in the foreground then it's not the best option – codeMagic Jul 20 '15 at 03:08
  • Save the current time stamp in onStop method in a shred preference(say EXIT). In onResume() check if the EXIT is less than 0, then you have to start from the beginning, if not then calculate the time Lapsed and start your counter from there. Below I have post the sample code for the same. – avinash Jul 22 '15 at 09:48

2 Answers2

0

Create a instance of CountDownTime in the activity as a static field variable:

    private static CountDownTime sCountDownTime = new CountDownTime(20000, 1000);

And start it in the activity anywhere you need:

    sCountDownTime.start(this);

This is the modified CountDownTime class, make it static so it doesn't hold a strong reference of the outter activity. You may need to remove the activity.isFinishing\isDestroyed if you want to execute the code even if the activity that started this counter is finished\destroyed(etc. user pressed back key).

    public static class CountDownTime extends CountDownTimer {

        private WeakReference<Activity> mActivityRef;
        private String mCurrentTime;
        private boolean mStarted;

        public CountDownTime(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
        }

        public void start(Activity activity) {
            mActivityRef = new WeakReference<Activity>(activity);
            if (!mStarted) {
                mStarted = true;
                start();
            } else {
                updateTextView();
            }
        }

        @Override
        public void onTick(long millisUntilFinished) {
            long millis = millisUntilFinished;
            mCurrentTime = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
                    TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
                    TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
            updateTextView();
        }

        @Override
        public void onFinish() {
            Activity activity = mActivityRef.get();
            if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
                activity.startActivity(new Intent(activity, SettingsActivity.class));
                activity.finish();
            }
            mStarted = false;
        }

        private void updateTextView() {
            Activity activity = mActivityRef.get();
            if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
                TextView textView = (TextView) activity.findViewById(R.id.text_view);
                textView.setText(mCurrentTime);
            }
        }
    }
wrkwrk
  • 2,261
  • 15
  • 21
  • Thanks for the help so far but I can't determine if the code works because I get an error : java.lang.NoSuchMethodError: android.app.Activity.isDestroyed. It has something to do with only running on device which are api 17 or higher, is there anyway around this? – leonardo Jul 20 '15 at 14:37
  • I build it on api 22. then remove the isDestoryed. isFinishing will also return true when activity has been destroyed. – wrkwrk Jul 20 '15 at 16:06
  • Ok it works now but if I hit home, wait a bit, then re access the application the timer starts from the beginning – leonardo Jul 20 '15 at 16:13
  • Well I don't know what is the desired behaviour of your app when it's in front\background, you can modify the code. A static countDownTime instance is the key that a new activity instance will not start the counter again. But if the activity keeps staying in the background, the system may kill the process to retrieve memory, in this case the coundownTimer will die, but since the process is died, it's reasonable that everything starts again. – wrkwrk Jul 21 '15 at 02:42
0

Try the following code. I took the count down of 3 min. I am saving the current time-stamp in onStop() in a preference, while in onResume() i am doing a small calculation to determine the time stapm from where the count down should start.

 public class MainActivity extends Activity {
TextView textView;
private CountDownTime countDownTimer;
private PreferenceManager manager;
private String EXIT="exit",TIME_LAPSED="timeLapsed";
private long millisInFuture=3*60*1000;
private long countDownInterval=1000;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    textView=(TextView)findViewById(R.id.textView1);
    manager=new PreferenceManager();


}
    @Override
      protected void onResume() {
super.onResume();
    if(manager.getLong(this, EXIT)<0){
countDownTimer=new CountDownTime(millisInFuture, 1000);
    }else{
         long time = manager.getLong(this,TIME_LAPSED)- (System.currentTimeMillis() -                               manager.getLong(this, EXIT)); 
    countDownTimer=new CountDownTime(time, countDownInterval);
            }
            Log.e("ONRESUME ", "CALLED");
             countDownTimer.start();
           }
 @Override
        protected void onStop() {
manager.put(this, EXIT, System.currentTimeMillis());
manager.put(this, TIME_LAPSED, millisInFuture);
countDownTimer.cancel();
super.onStop();
Log.e("ONSTOP ", "CALLED");
}
        public class PreferenceManager {
       private static final String PREF_NAME = "app_pref";
         public PreferenceManager() {};
           private  SharedPreferences getSharedPreferences(Context context) {
        return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
            }
         private  Editor getPreferenceEditor(Context context) {
        return getSharedPreferences(context).edit();
        }
    public  long getLong(Context context, String key) {
        return getSharedPreferences(context).getLong(key, -1);
        }
        public  void put(Context context, String key, long value) {
    Editor editor = getPreferenceEditor(context);
    editor.putLong(key, value);
    editor.commit();
}
 }
public class CountDownTime extends CountDownTimer {
   public CountDownTime(long millisInFuture, long countDownInterval) {
    super(millisInFuture, countDownInterval);
    }
   @Override
public void onTick(long millisUntilFinished) {
    millisInFuture = millisInFuture - 1000;
    long millis = millisUntilFinished;
    textView.setText(String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
            TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
            TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))));
}
    @Override
    public void onFinish() {
   /*Intent goBack = new Intent(CountDownAct.this, ListOfAlarms.class);
    startActivity(goBack);
    finish();*/
}
 } }
avinash
  • 1,744
  • 24
  • 40