Ravi Teja Ravi Teja - 3 months ago 37
Android Question

how to make a count down timer using service component in android?

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.fi`enter code here`ndItem(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;

Answer

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

}