I have a button that when pressed starts a countdown, and I want this countdown to continue until it ends even when the app is closed or changed from Activity
. I understand that one way to do it is to use a background service, but I have read but I can't understand how to implement it. Thank you !
class for service
package com.example.ash.carritosbeta1;
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.util.Log;
import java.util.concurrent.TimeUnit;
public class ServicioTimer extends Service {
String FORMAT = "%02d:%02d:%02d";
private static String TAG = "Servicio";
public static final String PAQETE = "com.example.ash.carritosbeta1"; //ejemplo com.proyecto.MainActivity
Intent bi = new Intent(PAQETE);
CountDownTimer cdt = null;
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "Comienza el timer...");
cdt = new CountDownTimer(9000, 1000) {
public void onTick(long millisUntilFinished) {
@SuppressLint("DefaultLocale") String tiempo = ""+String.format(FORMAT,
TimeUnit.MILLISECONDS.toHours(millisUntilFinished),
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) - TimeUnit.HOURS.toMinutes(
TimeUnit.MILLISECONDS.toHours(millisUntilFinished)),
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)));
//con esto se envia el tiempo
bi.putExtra("Tiempo", tiempo);
sendBroadcast(bi);
}
public void onFinish() {
//se envia el tiempo finalizado
bi.putExtra("Fin", "Tiempo terminado!");
sendBroadcast(bi);
}
}.start();
}
@Override
public void onDestroy() {
cdt.cancel();
Log.i(TAG, "Timer cancelado");
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;
}
}
Activities
public class tiempo_carro1 extends AppCompatActivity {
private static String TAG = "Servicio";
TextView contador;
Button inicar, pausar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tiempo_carro1);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
contador=(TextView)findViewById(R.id.mostrar);
contador.setText("00:00:00");
inicar=(Button)findViewById(R.id.iniciar);
inicar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//inicia el servicio
startService(new Intent(tiempo_carro1.this, ServicioTimer.class));
}
});
pausar=(Button)findViewById(R.id.Reinicar);
pausar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
private BroadcastReceiver br = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//aqui obtienes los datos enviados por el servicio
//obtienes el tiempo que lleva
if (intent.getExtras() != null) {
if (intent.hasExtra("Tiempo")) {
String tiempo = intent.getStringExtra("Tiempo");
contador.setText(tiempo);
} if (intent.hasExtra("Fin")) {
//se recibe que se ha finalizado el contador
String tiempo = intent.getStringExtra("Fin");
contador.setText(tiempo);
inicar.setEnabled(true);
//cierras el servicio ya que no es necesario mantenerlo, sera creado al pulsar el boton nuevamente
stopService(new Intent(tiempo_carro1.this, ServicioTimer.class));
}
}
}
};
@Override
public void onResume() {
super.onResume();
registerReceiver(br, new IntentFilter(ServicioTimer.PAQETE));
Log.i(TAG, "Broadcast registrado");
}
@Override
public void onPause() {
super.onPause();
unregisterReceiver(br);
Log.i(TAG, "Broadcast desligado");
}
@Override
public void onStop() {
try {
unregisterReceiver(br);
} catch (Exception ignored) {}
super.onStop();
}
@Override
public void onDestroy() {
stopService(new Intent(tiempo_carro1.this, ServicioTimer.class));
Log.i(TAG, "Termina el servicioo");
super.onDestroy();
}
}
I will explain to you the way in which I would do it, the operation is as follows; A service is created as you have indicated, which will be in charge of executing the countdown, it will be executed from the activity when pressing the button. In the same activity, a "listener" is created using a
BroadcastReceiver
which will receive information from the service such as elapsed time, or when it ends. If the activity is closed, the listener of said broadcast is eliminated, if it is destroyed, the service is terminated; These last behaviors can be modified according to your preference. The implementation could be as follows:SERVICE:
ACTIVITIES:
MANIFEST:
Ignore some small detail such as that you place
FORMAT
and order it to your preference and needs, I have taken the liberty of adding small comments in the code and Logs to help you identify things, any questions you can leave a comment and I will try to solve it as soon as possible.EDIT: To complement my answer, I add a link to the code on GitHub , the persistence issue is solved if the application is closed, and when re-opening it, the countdown continues.
If it doesn't run, it must be through the route that they put in the service in the manifest or it could be one of the possible errors since it happened to me, I put it inside a folder where I manage all the classes, so I couldn't find it the service and even so I ran the application but it did not show me the countdown