Reputation: 73
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
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:
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
.
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.onFinish()
function is called, inside which we call the serie
again but in REST mode.numar_pauza
seconds.onFinish()
function, we set the timer_free
variable to true. Also here we check if workoutCycles
is 0.serie
function in WORK mode. The process repeatsRead here about why we use Math.round
in onTick
Hope this helps.
Upvotes: 1
Reputation: 96
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.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