2010-02-24 18 views
7

Tengo un servicio ejecutándose en segundo plano. Cada vez que se inicia guardo en la memoria la hora de inicio en milisegundos:Android: cronómetro como un cronómetro persistente. Cómo establecer la hora de inicio? ¿Qué es el cronómetro "Base"?

startingTime = new Date().getTime(); 

Quiero mostrar un cronómetro que comienza a contar cuando se inicia el servicio y nunca se detiene hasta que el usuario pulsa 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 elapsedTime cada vez que el usuario retorno a la actividad cronómetro:

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

La cosa es que no sé cómo decirle al cronómetro para empezar a contar a partir de ese momento!

configurándolo como la base del cronómetro no funciona. ¿Puede alguien explicar qué significa exactamente "base" o cómo lograr esto?

muchas gracias! BYE

Respuesta

20

Puede usar Chronometer.

También debe marcar this thread.

EDIT: 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(); 
    } 
}; 
} 
+0

Sí, ya he visto eso y probado, pero el cronómetro no siempre obtienen resseted ... Se inicia a las 0:00 en cualquier momento! Ni siquiera puedo hacer que comience en un valor constante diferente a 0:00. – Santiago

+0

¡¡Gran respuesta amigo !!! Muchas gracias !!!! – Arun

+0

Gracias Macarse .... estaba buscando exactamente esto ... he pasado muchas horas en esto .... gracias amigo – shripal

4

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

1

alguna extraña con SystemClock.getElapsedTime(), hice algunos cambios para la normalidad utilizando la fecha de inicio, como

myChron.setBase(startDate.getTime()); 

Aquí hijo del 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. 
    * <p/> 
    * 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); 
     } 
    } 
} 

Simplemente copia y el uso , funciona para mí

+0

¿Podría explicar qué ha cambiado en la implementación de la clase de cronómetro del marco? – faizal

+0

http://stackoverflow.com/a/19774399/2590478 – MidasLefko

2

Para iniciar el cronómetro, debe utilizar el método setBase() de su cronómetro con SystemClock.elapsedRealTime(). Al igual que este:

mChronometer.setBase(SystemClock.elapsedRealTime()) 

Pero si desea iniciar en otro momento, usted tiene que restar el tiempo que desee en milisegundos.Por ejemplo, usted quiere comenzar su cronómetro en 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" tiempo antes de que comience para contar, para cambiarlo a su tiempo que tiene que hacer lo siguiente:

mChronometer.setText("02:00"); 
0

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(); 
1

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 milisecs desde el inicio. Cuando usa .stop, el recuento 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 transcurrido desde el inicio, debe obtener nuevamente el tiempo transcurrido del sistema y marcar la diferencia con .setTime

+0

¿Alguna sugerencia de cómo podemos implementar esto? SystemClock.elapsedRealtime() - mElapsedTime; no está trabajando – AndroidGuy

1

¿Cómo se establece la hora de inicio? ¿Qué es el cronómetro "Base"?

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

myChronometer.setBase(SystemClock.elapsedRealtime());