Android: cronómetro como un cronómetro persistente. Cómo establecer la hora de inicio? ¿Qué es el cronómetro “Base”?

Tengo un servicio ejecutándose en segundo plano. Siempre que comienza, almaceno en memoria la hora de inicio en milisegundos:

startingTime = new Date().getTime(); 

Quiero mostrar un cronómetro que comienza a contar cuando el servicio se inicia y nunca se detiene hasta que el usuario presiona un botón. Quiero permitir que el usuario abandone la actividad que representa el cronómetro, haga algunas cosas y luego regrese. Pero la idea es que cuando el usuario regrese no quiero que el cronómetro vuelva a ser 0:00. Insistido, quiero que muestre la hora exacta que ha pasado desde que comenzó el servicio.

Puedo calcular el tiempo transcurrido cada vez que el usuario regresa a la actividad del cronómetro:

 elapsedTime = new Date().getTime() - startingTime; 

¡El problema es que no sé cómo decirle al cronómetro que comience a contar a partir de ese momento!

Establecerlo como la base del cronómetro no funciona. ¿Puede alguien explicar qué significa exactamente “base” o cómo lograr esto?

¡muchas gracias! ADIÓS

Puedes usar el cronómetro .

También deberías verificar este hilo .

EDITAR: La solución:

 public class ChronoExample extends Activity { Chronometer mChronometer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); mChronometer = new Chronometer(this); // Set the initial value mChronometer.setText("00:10"); layout.addView(mChronometer); Button startButton = new Button(this); startButton.setText("Start"); startButton.setOnClickListener(mStartListener); layout.addView(startButton); Button stopButton = new Button(this); stopButton.setText("Stop"); stopButton.setOnClickListener(mStopListener); layout.addView(stopButton); Button resetButton = new Button(this); resetButton.setText("Reset"); resetButton.setOnClickListener(mResetListener); layout.addView(resetButton); setContentView(layout); } private void showElapsedTime() { long elapsedMillis = SystemClock.elapsedRealtime() - mChronometer.getBase(); Toast.makeText(ChronoExample.this, "Elapsed milliseconds: " + elapsedMillis, Toast.LENGTH_SHORT).show(); } View.OnClickListener mStartListener = new OnClickListener() { public void onClick(View v) { int stoppedMilliseconds = 0; String chronoText = mChronometer.getText().toString(); String array[] = chronoText.split(":"); if (array.length == 2) { stoppedMilliseconds = Integer.parseInt(array[0]) * 60 * 1000 + Integer.parseInt(array[1]) * 1000; } else if (array.length == 3) { stoppedMilliseconds = Integer.parseInt(array[0]) * 60 * 60 * 1000 + Integer.parseInt(array[1]) * 60 * 1000 + Integer.parseInt(array[2]) * 1000; } mChronometer.setBase(SystemClock.elapsedRealtime() - stoppedMilliseconds); mChronometer.start(); } }; View.OnClickListener mStopListener = new OnClickListener() { public void onClick(View v) { mChronometer.stop(); showElapsedTime(); } }; View.OnClickListener mResetListener = new OnClickListener() { public void onClick(View v) { mChronometer.setBase(SystemClock.elapsedRealtime()); showElapsedTime(); } }; } 

La hora base es el tiempo en que el Chronometer comenzó a funcionar. Puede configurarlo usando Chronometer.setBase() . Debería obtener la hora base utilizando SystemClock.getElapsedTime() . Llame a setBase() con la hora de inicio cada vez que se inicia el Chronometer . Si existe la posibilidad de que la Activity se destruya y vuelva a crear mientras el temporizador aún está activo, deberá mantener la hora base en algún lugar fuera de la Activity que posee el Chronometer .

Para iniciar el cronómetro, debe usar el método setBase() de su cronómetro con SystemClock.elapsedRealTime() . Solo así:

 mChronometer.setBase(SystemClock.elapsedRealTime()) 

Pero si quiere comenzar en otro momento, debe restar el tiempo que desea en milisegundos. Por ejemplo, desea iniciar su cronómetro a los 10 segundos:

 mChronometer.setBase(SystemClock.elapsedRealTime() - 10*1000); 

A los 2 minutos:

 mChronometer.setBase(SystemClock.elapsedRealTime() - 2*60*1000); 

Pero el problema aquí es que el cronómetro mostrará “00:00” antes de que comience a contar, para cambiarlo a su tiempo, debe hacerlo:

 mChronometer.setText("02:00"); 

Algo extraño con SystemClock.getElapsedTime (), hice algunos cambios para el uso normal con la fecha de inicio, como

 myChron.setBase(startDate.getTime()); 

Aquí hijo de cronómetro a continuación, TimeView

 import android.R; import android.content.Context; import android.content.res.TypedArray; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.Log; import android.widget.Chronometer; import android.widget.RemoteViews; import java.util.Formatter; import java.util.IllegalFormatException; import java.util.Locale; @RemoteViews.RemoteView public class TimeView extends Chronometer { private static final String TAG = "TimeView"; private long mBase; private boolean mVisible; private boolean mStarted; private boolean mRunning; private boolean mLogged; private String mFormat; private Formatter mFormatter; private Locale mFormatterLocale; private Object[] mFormatterArgs = new Object[1]; private StringBuilder mFormatBuilder; private OnChronometerTickListener mOnChronometerTickListener; private StringBuilder mRecycle = new StringBuilder(8); private static final int TICK_WHAT = 2; /** * Initialize this Chronometer object. * Sets the base to the current time. */ public TimeView(Context context) { this(context, null, 0); } /** * Initialize with standard view layout information. * Sets the base to the current time. */ public TimeView(Context context, AttributeSet attrs) { this(context, attrs, 0); } /** * Initialize with standard view layout information and style. * Sets the base to the current time. */ public TimeView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { mBase = System.currentTimeMillis(); updateText(mBase); } public void setBase(long base) { mBase = base; dispatchChronometerTick(); updateText(System.currentTimeMillis()); } /** * Return the base time as set through {@link #setBase}. */ public long getBase() { return mBase; } public void start() { mStarted = true; updateRunning(); } /** * Stop counting up. This does not affect the base as set from {@link #setBase}, just * the view display. * 

* This stops the messages to the handler, effectively releasing resources that would * be held as the chronometer is running, via {@link #start}. */ public void stop() { mStarted = false; updateRunning(); } /** * The same as calling {@link #start} or {@link #stop}. * * @hide pending API council approval */ public void setStarted(boolean started) { mStarted = started; updateRunning(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mVisible = false; updateRunning(); } @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); mVisible = visibility == VISIBLE; updateRunning(); } private synchronized void updateText(long now) { long seconds = now - mBase; seconds /= 1000; String text = DateUtils.formatElapsedTime(mRecycle, seconds); if (mFormat != null) { Locale loc = Locale.getDefault(); if (mFormatter == null || !loc.equals(mFormatterLocale)) { mFormatterLocale = loc; mFormatter = new Formatter(mFormatBuilder, loc); } mFormatBuilder.setLength(0); mFormatterArgs[0] = text; try { mFormatter.format(mFormat, mFormatterArgs); text = mFormatBuilder.toString(); } catch (IllegalFormatException ex) { if (!mLogged) { Log.w(TAG, "Illegal format string: " + mFormat); mLogged = true; } } } setText(text); } private void updateRunning() { boolean running = mVisible && mStarted; if (running != mRunning) { if (running) { updateText(System.currentTimeMillis()); dispatchChronometerTick(); mHandler.sendMessageDelayed(Message.obtain(mHandler, TICK_WHAT), 1000); } else { mHandler.removeMessages(TICK_WHAT); } mRunning = running; } } private Handler mHandler = new Handler() { public void handleMessage(Message m) { if (mRunning) { updateText(System.currentTimeMillis()); dispatchChronometerTick(); sendMessageDelayed(Message.obtain(this, TICK_WHAT), 1000); } } }; void dispatchChronometerTick() { if (mOnChronometerTickListener != null) { mOnChronometerTickListener.onChronometerTick(this); } } }

Solo copia y usa, funciona para mí

Cuando configura el tiempo base con .setBase (SystemClock.elapsedRealTime ()), el cronómetro comienza a contar desde 00.00, pero el tiempo que almacena es la cantidad de milisegundos desde el inicio. Cuando usa .stop, el conteo interno no se detiene, solo el tiempo que ve en el reloj. Por lo tanto, si usa .start nuevamente, la cuenta de reloj salta al recuento real. Si desea almacenar el tiempo que ha pasado desde el inicio, debe obtener nuevamente el tiempo transcurrido del sistema y marcar la diferencia con .setTime

Cómo establecer la hora de inicio? ¿Qué es el cronómetro “Base”?

Use SystemClock.elapsedRealtime() para este propósito:

  myChronometer.setBase(SystemClock.elapsedRealtime()); 

Esto funciona para mí:

 Date now = new Date(); long elapsedTime = now.getTime() - startTime.getTime(); //startTime is whatever time you want to start the chronometer from. you might have stored it somwehere myChronometer.setBase(SystemClock.elapsedRealtime() - elapsedTime); myChronometer.start();