Ganesh S
Ganesh S

Reputation: 31

Android - Calculate Time in Background Even When App is Closed

I have a textview which acts a an stepuptimer. I used a handler and updating it every second and its working perfectly. But when I close the app and open, the timer starts from "0". I want the time to be running background and when I opened the activity, the elapsed time should be displayed instead of starting from 0 again. The displaying time format is 00:00:00.

My code is

public class GoOnlinePage extends Activity { 

private TextView Tv_timer;
private Handler onlineTimeHandler = new Handler();
private long startTime = 0L;
private long timeInMilliseconds = 0L;
private long timeSwapBuff = 0L;
private long updatedTime = 0L;
private int mins;
private int secs;
private int hours;


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

    Tv_timer = (TextView) findViewById(R.id.txt_timer);

     startTime = SystemClock.uptimeMillis();

    onlineTimeHandler.post(updateTimerThread);


  }



  private Runnable updateTimerThread = new Runnable() {

    public void run() {

        timeInMilliseconds = SystemClock.uptimeMillis() - startTime;

        updatedTime = timeSwapBuff + timeInMilliseconds;

        secs = (int) (updatedTime / 1000);
        hours = secs / (60 * 60);
        mins = secs / 60;
        secs = secs % 60;
        if (mins >= 60) {
            mins = 0;
        }


        Tv_timer.setText(String.format("%02d", hours) + ":" + 
         String.format("%02d", mins) + ":"
                + String.format("%02d", secs));



        onlineTimeHandler.postDelayed(this, 1 * 1000);

    }

};

}

I tried using session and updating the time each second inside updateTimerThread. When I open back the app, I was getting the current time and finding difference between the two times and updating the timer back. But nothing worked.

Please help me. Thanks in Advance.

EDIT

SOLVED

I solved it by using a Service and updated the textview by using a BroadcastReceiver. I have attached the code below for your reference.

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;



public class TimerService extends Service {
    private static String LOG_TAG = "TimerService";
    private IBinder mBinder = new MyBinder();

    Handler onlineTimeHandler = new Handler();
    long startTime = 0L, timeInMilliseconds = 0L, timeSwapBuff = 0L, updatedTime = 0L;
    int mins, secs, hours;
    String time = "";

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.v(LOG_TAG, "in onCreate");
        startTime = SystemClock.uptimeMillis();
        onlineTimeHandler.post(updateTimerThread);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.v(LOG_TAG, "in onBind");
        return mBinder;
    }

    @Override
    public void onRebind(Intent intent) {
        Log.v(LOG_TAG, "in onRebind");
        super.onRebind(intent);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.v(LOG_TAG, "in onUnbind");
        return true;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.v(LOG_TAG, "in onDestroy");
        if(onlineTimeHandler!=null){
            onlineTimeHandler.removeCallbacks(updateTimerThread);
        }
    }


    public class MyBinder extends Binder {
        TimerService getService() {
            return TimerService.this;
        }
    }

    private Runnable updateTimerThread = new Runnable() {

        public void run() {

            timeInMilliseconds = SystemClock.uptimeMillis() - startTime;

            updatedTime = timeSwapBuff + timeInMilliseconds;

            secs = (int) (updatedTime / 1000);
            hours = secs / (60 * 60);
            mins = secs / 60;
            secs = secs % 60;
            if (mins >= 60) {
                mins = 0;
            }

            time = String.format("%02d", hours) + ":" + String.format("%02d", mins) + ":"
                    + String.format("%02d", secs);


            Intent intent = new Intent();
            intent.setAction("com.app.Timer.UpdateTime");
            intent.putExtra("time", time);
            sendBroadcast(intent);

            onlineTimeHandler.postDelayed(this, 1 * 1000);

        }

    };
}

Upvotes: 0

Views: 3360

Answers (4)

from56
from56

Reputation: 4127

Pretty simple using some static variable. This example continue counting even if the activity is in the background or destroyed, no SharedPreferences or Service needed :

public class MainActivity extends AppCompatActivity {

    private static TextView txtCounter;
    private static Handler handler;
    private static Runnable runnable ;
    private static int count;


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

        txtCounter = (TextView) findViewById(R.id.txtCounter);
        if (handler == null) {
            handler = new Handler();
            runnable = new Runnable() {
                @Override
                public void run() {
                    txtCounter.setText("Count = " + count);
                    count++;
                    handler.postDelayed(runnable, 1000);
                }
            };
            handler.postDelayed(runnable, 1000);
        }
    }

}

UPDATE:

To pause : handler.removeCallbacks(runnable);

To resume : handler.postDelayed(runnable, 1000);

To reset the counter : count = 0;

Upvotes: 2

Tolga Okur
Tolga Okur

Reputation: 7113

Store startTime value when your timer starts in some persistent place (like SharedPreferences etc.) and remove when your timer ends.

In your Activity#onCreate method, check that persistent value and if exists, initialise your startTime value with that instead of current system time.

Some tips for related to your code in question:

  • Use new Date().getTime() instead of SystemClock.uptimeMillis(). It makes your code more robust against reboots.
  • Stop your timer ticker when your Activity#onPause called and start when Activity#onResume called. Because of you don't need to update your UI while it's not visible.

Upvotes: 1

Charu
Charu

Reputation: 1075

There can be two ways to achieve this:

  1. You can use a Service for timer, it will keep running even if app is in the background or killed.
  2. Use SharedPreference and store the timer value when app is being killed and when app restarts, just fetch that value and sum it with the duration

Upvotes: 0

aman_41907
aman_41907

Reputation: 199

When your activity is destroyed Tv_timer object will also be destroyed, the one on which thread is updating.When the activity is started again new object of Tv_timer is created.

Also the time can be stored somewhere and used later when application is started

Upvotes: 0

Related Questions