androidcountdowntimer

How to keep a CountDownTimer running even if the app is closed?


I spent my summer learning how to code and building my first app (in android studio). Therefore I am not an expert coder. This week I encountered a problem. Basically, I am developing a quiz app and when the user gets the answer wrong he have to wait 5 min. The thing is that when the countdowntimer starts and the user closes the app (by closing the app I mean destroy it and not just push the home button) the countdowntimer stops. I am wondering how I can manage to keep the timer running even if the app is closed. Your help will be greatly appreciated and it would be fantastic if you guys give me a sample code. Thanks in advance!


Solution

  • Run it in a service as such: use create a broadcast receiver in your activity and have the service send broadcasts.

    package com.example.cdt;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.CountDownTimer;
    import android.os.IBinder;
    import android.util.Log;
    
    public class BroadcastService extends Service {
    
        private final static String TAG = "BroadcastService";
    
        public static final String COUNTDOWN_BR = "your_package_name.countdown_br";
        Intent bi = new Intent(COUNTDOWN_BR);
    
        CountDownTimer cdt = null;
    
        @Override
            public void onCreate() {       
                super.onCreate();
    
                Log.i(TAG, "Starting timer...");
    
                cdt = new CountDownTimer(30000, 1000) {
                    @Override
                    public void onTick(long millisUntilFinished) {
    
                        Log.i(TAG, "Countdown seconds remaining: " + millisUntilFinished / 1000);
                        bi.putExtra("countdown", millisUntilFinished);
                        sendBroadcast(bi);
                    }
    
                    @Override
                    public void onFinish() {
                        Log.i(TAG, "Timer finished");
                    }
                };
    
                cdt.start();
            }
    
            @Override
            public void onDestroy() {
    
                cdt.cancel();
                Log.i(TAG, "Timer cancelled");
                super.onDestroy();
            }
    
            @Override
            public int onStartCommand(Intent intent, int flags, int startId) {       
                return super.onStartCommand(intent, flags, startId);
            }
    
            @Override
            public IBinder onBind(Intent arg0) {       
                return null;
            }
    }
    

    From the main activity:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
        startService(new Intent(this, BroadcastService.class));
        Log.i(TAG, "Started service");
    }
    
    private BroadcastReceiver br = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {            
            updateGUI(intent); // or whatever method used to update your GUI fields
        }
    };
    
    @Override  
    public void onResume() {
        super.onResume();        
        registerReceiver(br, new IntentFilter(BroadcastService.COUNTDOWN_BR));
        Log.i(TAG, "Registered broacast receiver");
        }
    
    @Override
    public void onPause() {
        super.onPause();
        unregisterReceiver(br);
        Log.i(TAG, "Unregistered broacast receiver");
    }
    
    @Override
    public void onStop() {
        try {
            unregisterReceiver(br);
        } catch (Exception e) {
            // Receiver was probably already stopped in onPause()
        }
        super.onStop();
    }
    @Override
    public void onDestroy() {        
        stopService(new Intent(this, BroadcastService.class));
        Log.i(TAG, "Stopped service");
        super.onDestroy();
    }
    
    private void updateGUI(Intent intent) {
        if (intent.getExtras() != null) {
            long millisUntilFinished = intent.getLongExtra("countdown", 0);
            Log.i(TAG, "Countdown seconds remaining: " +  millisUntilFinished / 1000);            
        }
    }
    

    Note I got this code from How to run CountDownTimer in a Service in Android?, which I modified for my own android countDownTimer.