Implement a CountDown Timer in a service

1

I have a button that when pressed starts a countdown, and I want this account to be maintained until it ends even when the app closes or changes from Activity . I understand that one way to do it is to use a service in the background, but I have read but I can not understand how to implement it. Thanks!

Class for the 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;
    }
}

Activity

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();
    }
}
    
asked by Ashley G. 25.08.2017 в 03:19
source

1 answer

3

I'll explain to you how I would do it, the operation is as follows; A service is created as you have indicated, which will be responsible for executing the countdown, this will be executed from the activity by pressing the button. In the same activity, a "listening" is created using a BroadcastReceiver which will receive the information of the service such as the elapsed time, or when it ends. If the activity is closed, the listening 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:

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 = "nombre_de_tu_paquete.nombre_atividad"; //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) {
            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;
}
}

ACTIVITY:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

private static String TAG = "Servicio";

TextView contador;
Button iniciar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    contador = (TextView) findViewById(R.id.contador);
    iniciar = (Button) findViewById(R.id.iniciar);
    iniciar.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            iniciar.setEnabled(false);
            //inicia el servicio
            startService(new Intent(MainActivity.this, ServicioTimer.class));
        }
    });
}

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);
                iniciar.setEnabled(true);
                //cierras el servicio ya que no es necesario mantenerlo, sera creado al pulsar el boton nuevamente
                stopService(new Intent(MainActivity.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 e) {}
    super.onStop();
}
@Override
public void onDestroy() {
    stopService(new Intent(MainActivity.this, ServicioTimer.class));
    Log.i(TAG, "Termina el servicio");
    super.onDestroy();
}
}

MANIFEST:

<service android:name=".ServicioTimer"/>

Obtain some small detail like that you place your FORMAT and you order it to your preference and needs, I have taken the liberty to add small comments in the code and Logs so that they help you to identify the things, any doubt you can leave a comment and I will try to solve it as soon as possible.

EDIT: To complement my response, I added a link to the code on GitHub , the issue of persistence is solved if the application is closed, and when re-opening continue the countdown.

    
answered by 25.08.2017 / 06:31
source