Search code examples
androidbundleparcelablecountdowntimeronsaveinstancestate

Restore CountDownTimer object after rotation


When i rotate, onCreate method is called so i lose all of my vars , that's why i want to restore CountDownTimer object . The onTick and onFinish callback methods of CDT object are active as the countdownTimer keep running. I think the solution is to make parcable the object but i didn't manage to complete my code

I dont want to use Service coz the Android doc is spesific when to use Services and i think in my case i dont need a Service

   //my try to make parsable the CDT object    
    public class MyCountDownTimer implements Parcelable {
            private CountDownTimer t;

            public  final Parcelable.Creator CREATOR = new Parcelable.Creator() {
                public MyCountDownTimer createFromParcel(Parcel in) {
                    return new MyCountDownTimer(in);
                }

                public MyCountDownTimer[] newArray(int size) {
                    return new MyCountDownTimer[size];
                }
            };

            private MyCountDownTimer(Parcel in) {
                t = (CountDownTimer) in.readParcelable(Timer);
            }
            MyCountDownTimer(CountDownTimer t)
            {
                this.t =t;
            }

            @Override
            public int describeContents() {
                return 0;
            }

            @Override
            public void writeToParcel(Parcel parcel, int i) {

            }
        }


    //declaretion
    private CountDownTimer Timer;

    protected void onSaveInstanceState(@NonNull Bundle outState){
         super.onSaveInstanceState(outState);
         outState.putSerializable(COUNTDOWN,new MyCountDownTimer(Timer));
    }

    //on restore
    Timer = (CountDownTimer) savedInstanceState.getParcelable(COUNTDOWN);


    //when call Timer
     private void setTimer(long mTimeLeftInMillisfun){

            Timer = new CountDownTimer(mTimeLeftInMillisfun,1000) {
                @Override
                public void onTick(long l) {


                    textTimer.setText("Remain "+ l/1000+" Seconds");

                }

                @Override
                public void onFinish() {
                    //do sth
                }


            }.start();
        }

Solution

  • Don't parcel your timer. You will lose time on clock (may not be a lot but still) during parcel/unparcel process.

    Use a ViewModel to survive your timer during configuration change (activity rotation).

    https://developer.android.com/topic/libraries/architecture/viewmodel

    Sample code -

    public class MyViewModel extends ViewModel {
    
    private CountDownTimer countDownTimer;
    private MutableLiveData<Long> timerLiveData;
    
    public MyViewModel() {
        this.timerLiveData = new MutableLiveData<>();
    }
    
    public LiveData<Long> getTimerLiveData() {
        return timerLiveData;
    }
    
    public void requestTimer(long timeInMins) {
        if (countDownTimer != null) {
            countDownTimer.cancel();
        }
    
        countDownTimer = new CountDownTimer(timeInMins * 60 * 1000, 1000) {
    
            public void onTick(long millisUntilFinished) {
                timerLiveData.setValue(millisUntilFinished);
            }
    
            public void onFinish() {
                timerLiveData.setValue(0L);
            }
        };
        countDownTimer.start();
    }
    

    }

    Listen to timer from UI -

    myViewModel.getTimerLiveData().observe(this, timeLeft -> Log.d("test", "timeLeft " + timeLeft);