0

I am trying to build an app in which the action bar has a countdown timer view. I succeeded in doing it but, when I close the app and reopen, the countdown restarts. What I need is the countdown should not stop till it completes its time even if I close or minimize the app. I tried this code:

  final long[] timer = {2700000};
      getMenuInflater().inflate(R.menu.menu_main, menu);
      final MenuItem  counter = menu.findItem(R.id.counter);
      new CountDownTimer(timer[0], 1000) {

        public void onTick(long millisUntilFinished) {
            long millis = millisUntilFinished;
            String  hms =  (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)));

            counter.setTitle(hms);
            timer[0] = millis;

        }

        public void onFinish() {
            counter.setTitle("done!");
        }
    }.start();
    return true;
Maddy
  • 4,525
  • 4
  • 33
  • 53
Ravi Teja
  • 3
  • 3

2 Answers2

1

Mr. donnfelker Had written countdown timer service on his bootstrap android demo. given link is open source Android bootstrap you will find this service class. will give you hint for how this will done.

public class TimerService extends Service {

@Inject protected Bus eventBus;
@Inject NotificationManager notificationManager;

private boolean timerRunning = false;
private boolean timerStarted;
private long base;
private long currentRunningTimeInMillis;
private long pausedBaseTime;
private boolean isPaused;

public static final int TICK_WHAT = 2;
private NotificationCompat.Builder b;
private String messageFormat;

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    super.onCreate();

    BootstrapApplication.component().inject(this);

    // Register the bus so we can send notifications.
    eventBus.register(this);

}

@Override
public void onDestroy() {

    // Unregister bus, since its not longer needed as the service is shutting down
    eventBus.unregister(this);

    notificationManager.cancel(TIMER_NOTIFICATION_ID);

    Timber.d("Service has been destroyed");

    super.onDestroy();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    if (!timerStarted) {

        timerStarted = true;

        startTimer();

        // Run as foreground service: http://stackoverflow.com/a/3856940/5210
        // Another example: https://github.com/commonsguy/cw-android/blob/master/Notifications/FakePlayer/src/com/commonsware/android/fakeplayerfg/PlayerService.java
        startForeground(TIMER_NOTIFICATION_ID, getNotification(getString(R.string.timer_running)));
    }

    return START_NOT_STICKY;
}

@Produce
public TimerTickEvent produceTickEvent() {
    updateNotification(getTimerRunningMessage(currentRunningTimeInMillis));
    return new TimerTickEvent(currentRunningTimeInMillis);
}

@Produce
public TimerPausedEvent produceTimerIsPausedEvent() {
    return new TimerPausedEvent(isPaused);
}

@Subscribe
public void onStopEvent(StopTimerEvent stopEvent) {

    timerHandler.removeMessages(TICK_WHAT);
    stopSelf();
}

@Subscribe
public void onPauseEvent(PauseTimerEvent pauseEvent) {
    pauseTimer();
}

/**
 * Pauses the active running timer and updates the notification in the status bar.
 */
private void pauseTimer() {

    updateNotification(getString(R.string.timer_is_paused));

    timerHandler.removeMessages(TICK_WHAT);
    pausedBaseTime = SystemClock.elapsedRealtime() - base;
    timerRunning = false;
    isPaused = true;

    produceTimerIsPausedEvent();
}

@Subscribe
public void onResumeTimerEvent(ResumeTimerEvent resumeTimerEvent) {
    startTimer();
}

private void startTimer() {
    startChronoTimer();
    notifyTimerRunning();
}

private void startChronoTimer() {
    base = SystemClock.elapsedRealtime();

    // If coming from a paused state, then find our true base.
    if (pausedBaseTime > 0)
        base = base - pausedBaseTime;

    isPaused = false;

    updateRunning();
}

/**
 * Starts the generic timer.
 */
private void updateRunning() {
    if (timerStarted != timerRunning) {
        if (timerStarted) {
            dispatchTimerUpdate(SystemClock.elapsedRealtime());
            timerHandler.sendMessageDelayed(Message.obtain(timerHandler, TICK_WHAT), 1000);
        } else {
            timerHandler.removeMessages(TICK_WHAT);
        }
        timerRunning = timerStarted;
    }
}

private Handler timerHandler = new Handler() {
    public void handleMessage(Message m) {
        if (timerRunning) {
            dispatchTimerUpdate(SystemClock.elapsedRealtime());
            sendMessageDelayed(Message.obtain(this, TICK_WHAT), 1000);
        }
    }
};

private void dispatchTimerUpdate(long now) {

    currentRunningTimeInMillis = now - base;
    Timber.d("Elapsed Seconds: " + currentRunningTimeInMillis / 1000);

    eventBus.post(produceTickEvent());

}


private void notifyTimerRunning() {
    updateNotification(getTimerRunningMessage(currentRunningTimeInMillis));
    produceTimerIsPausedEvent();
}

private String getTimerRunningMessage(long millis) {
    if(Strings.isEmpty(messageFormat)) {
        messageFormat = getString(R.string.timer_running);
    }

    return String.format(messageFormat, TimeUtil.formatTime(millis));
}


private void updateNotification(String message) {
    notificationManager.notify(TIMER_NOTIFICATION_ID, getNotification(message));

}

/**
 * Creates a notification to show in the notification bar
 *
 * @param message the message to display in the notification bar
 * @return a new {@link Notification}
 */
private Notification getNotification(String message) {
    final Intent i = new Intent(this, BootstrapTimerActivity.class);

    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, i, 0);

    if(Strings.notEmpty(message)) {
        return getNotificationBuilder(message, pendingIntent)
                .setContentText(message)
                .build();
    } else {
        return getNotificationBuilder(message, pendingIntent).build();
    }
}

/**
 * Resuse the same notification builder.
 * @param message
 * @param pendingIntent
 * @return
 */
private NotificationCompat.Builder getNotificationBuilder(String message, PendingIntent pendingIntent) {
    if(b == null) {
        b = new NotificationCompat.Builder(this)
                .setContentTitle(getString(R.string.app_name))
                .setSmallIcon(R.drawable.ic_stat_ab_notification)
                .setContentText(message)
                .setAutoCancel(false)
                .setOnlyAlertOnce(true)
                .setOngoing(true)
                .setWhen(System.currentTimeMillis())
                .setContentIntent(pendingIntent);
    }
    return b;
}

}

Himeshgiri gosvami
  • 2,559
  • 4
  • 16
  • 28
0

If you want to it in activity. Check below demo

MainActivity:

public class MainActivity extends AppCompatActivity {

    Context context;
    private SharedPreferences mPrefs;
    private CountDownTimer countDownTimer;
    // here is prefs key
    String Key = "TIME";
    long time = 30000; // 30 sec
    EditText number;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = this;

        number = (EditText) findViewById(R.id.foodName);
        mPrefs = this.getSharedPreferences("myAppPrefs", Context.MODE_PRIVATE);
        if (mPrefs.getLong(Key, 0) == 0) {
            mPrefs.edit().putLong(Key, time).apply();
        } else {
            time = mPrefs.getLong(Key, time);
        }
        Log.d("App Open Time ", time + "");
        startCount();


    }

    private void startCount() {
        countDownTimer = new CountDownTimer(time, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                mPrefs.edit().putLong(Key, millisUntilFinished).apply();
                number.setText(millisUntilFinished/1000 + "");
                Log.d("Remaining time", millisUntilFinished/1000 + "");
            }

            @Override
            public void onFinish() {
                Log.d("finished  time", time + "");
                mPrefs.edit().putLong(Key, 0).apply();
                number.setText(time + "");
            }
        };
        countDownTimer.start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        countDownTimer.cancel();
        Log.d("App in background", "with " + time);
    }
}

layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/base"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="10dp"
    android:background="@color/white"
    android:orientation="horizontal"
    android:weightSum="10">


    <EditText
        android:id="@+id/foodName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="64dp"
        android:layout_marginRight="64dp"
        android:hint="Food name"
        android:inputType="textCapWords"
        android:textColor="@color/colorPrimaryDark"
        android:textColorHint="@color/colorPrimaryDark"
        android:textSize="32sp"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

Manifest:

<activity
        android:name=".activity.MainActivity"
        android:configChanges="orientation|screenSize">
</activity>
Sohail Zahid
  • 8,099
  • 2
  • 25
  • 41
  • I tried your code..it's working...the EditText starts countdown timer and pauses when i close the app and on reopening it resumes...but i want the EditText to continue (background) countdown even i close the app(It shouldn't pause).. – Ravi Teja Sep 02 '16 at 04:25
  • @SohailZahid . would you please answer this question? http://stackoverflow.com/q/41045576/7268725 – Mina Dahesh Dec 10 '16 at 06:23