¿Cómo se puede pausar el cronómetro periódicamente en segundo plano en la programación de Android?
Eché un vistazo al código fuente de la clase Chronometer. Internamente, utiliza un controlador para enviarse un mensaje a sí mismo con un retraso de un segundo y luego modifica la hora. Al presionar el botón Inicio se activará el método onWindowVisibilityChanged() de Chronometer
Los métodos principales son los siguientes:
public?void?start()?{
mStarted?=?true;
updateRunning();
}
El método anterior consiste en iniciar el temporizador, establecer la variable mStarted en verdadero y ejecutar El método updateRunning once (), updateRunning() se analizará a continuación
public?void?stop()?{
mStarted?=?false;
updateRunning (
}
El método stop() es detener el tiempo, establecer la variable mStarted en falso y ejecutar el método updateRunning() una vez. p>protegido?void? onWindowVisibilityChanged(int?visibilidad)?{
super.onWindowVisibilityChanged(visibilidad);
mVisible?=?visibilidad?==?VISIBLE;
updateRunning() ;
}
El método onWindowVisibilityChanged anterior es un método en View. Este método se activará siempre que cambie el estado visible de View. que presionar el botón Inicio no se detiene, porque el código en este método en realidad se debe a que después de presionar el botón Inicio para activar este método, ya no se volverá a llamar al método de devolución de llamada del oyente que configuró. Después de presionar el botón Inicio, la Vista se vuelve invisible y la variable mVisible se vuelve falsa
private?void?updateRunning()?{
boolean?running?=?mVisible?amp ;amp ;?mIniciado;
if?(¿en ejecución?!=?mEn ejecución)?{
if?(en ejecución)?{
updateText(SystemClock. elapsedRealtime( ));
dispatchChronometerTick();
mHandler.sendMessageDelayed(Message.obtain(mHandler,?TICK_WHAT),?1000);
}? {
mHandler.removeMessages(TICK_WHAT);
}
mRunning?=?running;
}
}
El método updateRunning()? anterior utiliza principalmente dos variables booleanas, mVisible y mStarted, para controlar si se envían mensajes al controlador.
¿privado?Handler?mHandler?=?new?Handler()?{
público?void?handleMessage(Message?m)?{
si?(mRunning)?{ p>
updateText(SystemClock.elapsedRealtime());
dispatchChronometerTick();
sendMessageDelayed(Message.obtain(this,?TICK_WHAT),?1000); p>
p>
}
}
};
Este controlador ejecuta principalmente el método despachoChronometerTick() y luego envía un mensaje retrasado. a sí mismo
void?dispatchChronometerTick()?{
if?(mOnChronometerTickListener?!=?null)?{
mOnChronometerTickListener.onChronometerTick(this);
}
}
¿El método despachoChronometerTick()? Es para volver a llamar el método onChronometerTick del oyente que configuró
Según Según el análisis anterior, después de presionar el botón Inicio, Chronometer no volverá a llamar a su método de escucha. Esto está controlado por el método onWindowVisibilityChanged() de Chronometer, por lo que su problema no es fácil de resolver. !
La solución que se me ocurre es tomar el código de Chronometer, escribir una clase yo mismo, pegar el código en Chronometer y luego modificar su método onWindowVisibilityChanged(), y luego puedes usar el tuyo propio. apagado. Lo probé y lo implementé
Finalmente, adjunto mi propio código de clase MyChronometer, puedes copiarlo. .
Utilice este control directamente en el archivo de diseño
package?com.lily.demo_listview;
/* *?Copyright?(C)?2008?The?Android?Open?Source? Proyecto * *?Licencia?bajo?la?Licencia?Apache?,?Versión?2.0?(la?Licencia?*?Puede?obtener?una?copia?de?la?Licencia?en * *?.android.internal.R.styleable.Chronometer,?defStyle,?0);
//setFormat(a.getString(com.android.internal.R.styleable.Chronometer_format));
//a.recycle();
init();
p>
}
privado?void?init ()?{
mBase?=?SystemClock.elapsedRealtime();
updateText(mBase) ;
}
/* *
?*?Establece?el?tiempo?que?el?temporizador?de?cuenta?adelante?está?en?referencia.
?*
?*?@param?base?Utilizar?{@link?SystemClock#elapsedRealtime}?time?base.
?*/
public?void?setBase(long ?base)?{
mBase?=?base;
despachoChronometerTick();
Log.d("MiCronómetro",?"dispatchChronometerTick?333" );
updateText(SystemClock.elapsedRealtime());
}
/**
?*?Volver?el? base?time?as?set?through?{@link?#setBase}.
?*/
public?long?getBase()?{
return?mBase;
}
/**
?* ?Establece?la?cadena?de?formato?utilizada?para?la?visualización.?El? ¿El cronómetro?mostrará
?*?esta?cadena,?con?los?primeros?s"?reemplazados? por?el?valor?actual?del?cronómetro?en
?*?"MM:SS"?o?"H:MM:SS"?formulario.
?* p>
?*?Si?la?cadena?de?formato?
es?nulo,?o?si?nunca?llama?setFormat(),?el
?*?Cronómetro?simplemente?mostrará?el?valor?del?temporizador?en?"MM: SS"?o?"H:MM:SS"
?*?formulario.
?*
?*?@param?formato?el? format?string.
?*/
public?void?setFormat(String?format)?{
mFormat?=?format;
if?(format?=?null?&?mFormatBuilder?==?null)?{
mFormatBuilder?=?new?StringBuilder(format.length()?*? 2);
}
}
/**
?*?Devuelve?la?cadena?de?formato?actual?como ?establecida? a través de?{@link?#setFormat}.
?*/
public?String?getFormat()?{
return?mFormat; >
}
/**
?*?Configura?el?oyente?para?ser?llamado?cuando?cambia?el?cronómetro. p>
?*?
?*?@param?listener?The?listener.
?*/
public?void?setOnChronometerTickListener( OnChronometerTickListener?listener )?{
mOnChronometerTickListener?=?listener;
}
/**
?*?@return? ?(¿puede?ser?nulo)?eso?es?escuchar?el?cambio?de?cronómetro
?*?eventos.
?*/
público ?OnChronometerTickListener?getOnChronometerTickListener()?{
return?mOnChronometerTickListener;
}
/**
?*? ?arriba.?Esto?no?afecta?la?base?como?configurada?desde?{@link?#setBase},?sólo
?*?la?visualización?de?vista. p>
?*?
?*?El cronómetro?funciona?programando?mensajes?regularmente?al?manipulador,?incluso?cuando?
?*?Widget?no?visible?
e.?Para?asegurarse?de?que?no?ocurrieran?fugas?de?recursos,?el?usuario?debería?
?*?asegurarse?de?que?cada?llamada?start()? ¿tiene?una?llamada?reciproca?a?{@link?#stop}.?
?*/
public?void?start()?{
mStarted?=?true;
updateRunning();
}
/**
?*?Stop?counting ?arriba.?Esto?no?afecta?la?base?como?configurada?desde?{@link?#setBase},?sólo
?*?la?visualización?de?vista. p>
?*?
?*?Esto?detiene?los?mensajes?al?controlador,?liberando?efectivamente?recursos?que?
? *?ser?sostenido?mientras?el?cronómetro?está?en?funcionamiento,?vía?{@link?#start}.?
?*/
pública?void?parada ()?{
mIniciado?=?false;
updateRunning();
}
/**
?*?¿Lo mismo?que?llamar?{@link?#start}?o?{@link?#stop}.
?*?@hide?pending?API?council ?aprobación
?*/
pública?void?setStarted(boolean?started)?{
mStarted?=?started;
updateRunning();
}
@Override
protected?void?onDetachedFromWindow()?{
super.onDetachedFromWindow() ;
mVisible?=?false;
updateRunning();
Log.d("MyChronmeter",?"onDetachedFromWindow()" mVisible);
}
@Override
protected?void?onWindowVisibilityChanged(int?visibility)?{
super.onWindowVisibilityChanged(visibilidad);
updateRunning();
}
¿privado?sincronizado?void?updateText(long?now)?{
¿long?segundos? =?ahora?-?mBase;
segundos?/=?
1000;
String?text?=?DateUtils.formatElapsedTime(mRecycle,?segundos);
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;
¿intentar?{
mFormatter.format(mFormat,?mFormatterArgs);
texto ?=?mFormatBuilder.toString();
}?catch?(IllegalFormatException?ex)?{
if?(!mLogged)?{
Registrar .w(TAG,?"Illegal?format?string:?"? ?mFormat);
mLogged?=?true;
}
}
}
setText(texto);
}
privado?void?updateRunning()?{
boolean?running?=?mStarted;
if?(running?!=?mRunning)?{
if?(running)?{
updateText( SystemClock.elapsedRealtime());
despachoChronometerTick();
Log.d("MyChronometer",?"dispatchChronometerTick?222");
mHandler. sendMessageDelayed(Message.obtain(mHandler,?TICK_WHAT),?1000);
}?else?{
mHandler.removeMessages(TICK_WHAT);
}
mRunning?=?running;
}
}
privado?Handler?mHandler?=?new?Handler()? {
public?void?handleMessage(Message?m)?{
if?(mRunning)?{
updateText(SystemClock.elapsedRealtime());
despachoChronometerTick();
Log.d("MyChronometer",? "dispatchChronometerTick?111");
sendMessageDelayed(Message.obtain(this,? TICK_WHAT),?1000);
}
}
};
void?dispatchChronometerTick()?{
if?(mOnChronometerTickListener?=?null)?{
mOnChronometerTickListener.onChronometerTick(this);
//Log.d("MyChronometer",?"Método de devolución de llamada " );
}
}
@SuppressLint("NewApi")?@Override
public?void?onInitializeAccessibilityEvent(AccessibilityEvent ? evento)?{
super.onInitializeAccessibilityEvent(evento);
evento.setClassName(MyChronometer.class.getName());
}
@SuppressLint("NewApi")?@Override
public?void?onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo?info)?{
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(MyChronometer.class.getName());
}
}