Alec
Alec

Reputation: 73

How do I make a countdown repeat?

I wanted to make a workout app that counts the working seconds and the rest seconds based on user input (user inputs only the work seconds). I tried to create a loop (in this case, for testing, running only 2 times where I call serie() ). This function takes an int as a param. and displays a countdown from that variable to 0. In my loop I call this 2 times ( once for the working seconds and once for rest seconds). In the loop the countdown takes place only for the rest seconds (maybe because it is already initialized, and doesn't depend on user input ??) and after it hits 0 it doesn't repeat. In the first screen the user types in a number of secs. and presses the submit button. After that the second activity will run where this code is. There isn't a problem with the passing of variables between activities.

main activity code :

package com.example.cronometru;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

public static final String sec_pass = "com.example.cronometru.sec_pass";

int work_seconds;
EditText secunde_input;

Button start_w;

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

    secunde_input = (EditText) findViewById(R.id.numar_secunde_work);
    start_w = (Button) findViewById(R.id.btn_start);
    start_w.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            work_seconds = Integer.valueOf(secunde_input.getText().toString());

            openWorkout();

        }
    });


}

public void openWorkout(){
    Intent intent = new Intent(this, Activity2.class);
    intent.putExtra(sec_pass, work_seconds);
    startActivity(intent);
}

private void showToast (String txt){
    Toast.makeText(MainActivity.this, txt, Toast.LENGTH_SHORT).show();
}

}

the second activity code :

  package com.example.cronometru;

  import androidx.appcompat.app.AppCompatActivity;

  import android.content.Intent;
  import android.os.Bundle;
  import android.os.CountDownTimer;
  import android.view.View;
  import android.widget.TextView;

  import java.sql.Time;
  import java.util.Locale;
  import java.util.concurrent.TimeUnit;
  
  public class Activity2 extends AppCompatActivity {

TextView timer;
boolean timer_free = true;
int numar_pauza = 5;
int workout_cycles = 0;
int numar_work;
long interval = 1000;

private int work = 0;
private  int rest = 1;

public void serie (int numar_secude, int mode){
    if(mode == work && timer_free){
        timer_free = false;
        new CountDownTimer(numar_secude * 1000 , interval) {
            @Override
            public void onTick(long l) {
                String sDuration = String.format(Locale.ENGLISH, "%02d : %02d", TimeUnit.MILLISECONDS.toMinutes(l),TimeUnit.MILLISECONDS.toSeconds(l) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(l)));
                timer.setText(sDuration);
            }

            @Override
            public void onFinish() {
                serie(numar_pauza, rest);
            }
        }.start();
    }
    else if (mode == rest){
        new CountDownTimer(numar_secude * 1000 , interval  ) {
            @Override
            public void onTick(long w) {
                String sDuration = String.format(Locale.ENGLISH, "%02d : 
           %02d", TimeUnit.MILLISECONDS.toMinutes(w),TimeUnit.MILLISECONDS.toSeconds(w) - 
           TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(w)));
                timer.setText(sDuration);
            }

            @Override
            public void onFinish() {

                timer_free = true;
                workout_cycles--;
                if(workout_cycles > 0 ){
                    serie(numar_work, work);
                }
            }
        }.start();
    }

}

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



    Intent intent = getIntent();
    numar_work = intent.getIntExtra(MainActivity.sec_pass, 0);

    timer = findViewById(R.id.textView);
    int i = 0;
    workout_cycles = 2;
    serie(numar_work, work);

}

}

Where is the problem ? Any ideas on doing things differently?

Upvotes: 2

Views: 299

Answers (2)

Abhi_J
Abhi_J

Reputation: 2129

Hi to start the rest counter right after the work counter, start the rest counter inside onfinish() of work counter.

The CountDownTimer doesn't block execution of the for loop so in effect you are creating six (2x3) CountDownTimer objects almost immediately and they are all updating the same output TextView timer.

Try something like this:

int numar_pauza = 30;
int numar_work;
int workoutCycles = 0;
private final long CD_INTERVAL = 500;

private final int WORK = 0;
private final int REST = 1;

boolean timer_free = true;


public void serie (int numar_secude, int mode){
    if(mode == WORK && timer_free){
      timer_free = false;
      new CountDownTimer(numar_secude * 1000 , CD_INTERVAL) {
        @Override
        public void onTick(long l) {
            timer.setText("" + String.valueOf(Math.round(l* 0.001f)));
        }

        @Override
        public void onFinish() {
            serie(numar_pauza, REST);
        }
      }.start();
    }
    else if(mode == REST){
      new CountDownTimer(numar_secude * 1000 , CD_INTERVAL) {
        @Override
        public void onTick(long l) {
            timer.setText("" + String.valueOf(Math.round(l* 0.001f)));
        }

        @Override
        public void onFinish() {
           timer_free = true;
           workoutCyclesRemaining--;
           if(workoutCyclesRemaining > 0){
             serie(numar_work, WORK);
           }
        }
      }.start();
}

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

    Intent intent = getIntent();
    numar_work = intent.getIntExtra(MainActivity.sec_pass, 0);

    timer = findViewById(R.id.textView);

    workoutCycles = 2;
    serie(numar_work, WORK);
}

Here, we make the serie function to work in two modes:

  1. to start workout counter
  2. to start rest counter

we pass the mode as an argument during function call. Also we need to make sure the next counter is started only after one workout-rest cycle is completed and no other timer is running. So lets keep a global boolean called timer_free.

Now for testing you want execute the workout-rest cycle twice, so lets use a gobal variable workoutCycles.

  1. First the serie functions called in WORK mode. This sets the boolean timer_free to false so no other workout-timer is started till this cycle finishes. It then starts the timer to count down for numar_work seconds.
  2. When the countdown stops the onFinish() function is called, inside which we call the serie again but in REST mode.
  3. This starts a new timer with to count down for numar_pauza seconds.
  4. When this timer finishes and calls its onFinish() function, we set the timer_free variable to true. Also here we check if workoutCycles is 0.
  5. If its not we need to perform another workout-cycle so we call serie function in WORK mode. The process repeats

Read here about why we use Math.round in onTick

Hope this helps.

Upvotes: 1

Jennifer Kiesel
Jennifer Kiesel

Reputation: 96

  1. You don't call it only twice, your loop for(int i = 0; i <= 2; i++) goes from 0 to 2 -> 3 times. I also don't understand why you use this loop - it will set the same text multiple (currently 3) times on the same textView.
  2. You assign both the calculated values to the same textView. If you replace the timer.setText("" + l / 1000); with a log statement you will see, that all the timer instances are working correctly.

I would add a second parameter to your serie method to indicate which textView you want to set the text on.

Upvotes: 0

Related Questions