¿Cómo ejecutar un hilo Runnable en Android a intervalos definidos?

Desarrollé una aplicación para mostrar texto a intervalos definidos en la pantalla del emulador de Android. Estoy usando la clase Handler . Aquí hay un fragmento de mi código:

 handler = new Handler(); Runnable r = new Runnable() { public void run() { tv.append("Hello World"); } }; handler.postDelayed(r, 1000); 

Cuando ejecuto esta aplicación, el texto se muestra solo una vez. ¿Por qué?

La solución simple para tu ejemplo es:

 handler = new Handler(); final Runnable r = new Runnable() { public void run() { tv.append("Hello World"); handler.postDelayed(this, 1000); } }; handler.postDelayed(r, 1000); 

O podemos usar hilo normal por ejemplo (con Runner original):

 Thread thread = new Thread() { @Override public void run() { try { while(true) { sleep(1000); handler.post(this); } } catch (InterruptedException e) { e.printStackTrace(); } } }; thread.start(); 

Puede considerar su objeto ejecutable como un comando que se puede enviar a la cola de mensajes para su ejecución, y el controlador como solo un objeto auxiliar utilizado para enviar ese comando.

Más detalles están aquí http://developer.android.com/reference/android/os/Handler.html

Creo que puede mejorar la primera solución de Alex2k8 para la actualización correcta cada segundo

1. Código original:

 public void run() { tv.append("Hello World"); handler.postDelayed(this, 1000); } 

2. Análisis

  • En el costo anterior, suponga que tv.append("Hello Word") cuesta T milisegundos, después de mostrar 500 veces el tiempo de demora es de 500 * T milisegundos
  • Aumentará retrasado cuando se ejecuta mucho tiempo

3. Solución

Para evitar eso, solo cambie el orden de postDelayed (), para evitar el retraso:

 public void run() { handler.postDelayed(this, 1000); tv.append("Hello World"); } 
 new Handler().postDelayed(new Runnable() { public void run() { // do something... } }, 100); 

Creo que para este caso típico, es decir, ejecutar algo con un intervalo fijo, Timer es más apropiado. Aquí hay un ejemplo simple:

 myTimer = new Timer(); myTimer.schedule(new TimerTask() { @Override public void run() { // If you want to modify a view in your Activity MyActivity.this.runOnUiThread(new Runnable() public void run(){ tv.append("Hello World"); }); } }, 1000, 1000); // initial delay 1 second, interval 1 second 

Usar el Timer tiene algunas ventajas:

  • El retardo inicial y el intervalo se pueden especificar fácilmente en los argumentos de la función de schedule
  • El temporizador se puede detener simplemente llamando myTimer.cancel()
  • Si desea tener solo un hilo ejecutándose, recuerde llamar a myTimer.cancel() antes de progtwigr uno nuevo (si myTimer no es nulo)

Para repetir la tarea, puede usar

 new Timer().scheduleAtFixedRate(task, runAfterADelayForFirstTime, repeaingTimeInterval); 

llámalo como

 new Timer().scheduleAtFixedRate(new TimerTask() { @Override public void run() { } },500,1000); 

El código anterior se ejecutará la primera vez después de medio segundo (500) y se repetirá después de cada segundo (1000)

Dónde

tarea es el método a ser ejecutado

después del tiempo para la ejecución inicial

( intervalo el tiempo para repetir la ejecución)

En segundo lugar

Y también puede usar CountDownTimer si desea ejecutar un número de Tarea de veces.

  new CountDownTimer(40000, 1000) { //40000 milli seconds is total time, 1000 milli seconds is time interval public void onTick(long millisUntilFinished) { } public void onFinish() { } }.start(); //Above codes run 40 times after each second 

Y también puedes hacerlo con Runnable. crear un método ejecutable como

 Runnable runnable = new Runnable() { @Override public void run() { } }; 

Y llámalo de ambas maneras

 new Handler().postDelayed(runnable, 500 );//where 500 is delayMillis // to work on mainThread 

O

 new Thread(runnable).start();//to work in Background 
 Handler handler=new Handler(); Runnable r = new Runnable(){ public void run() { tv.append("Hello World"); handler.postDelayed(r, 1000); } }; handler.post(r); 

Si entiendo correctamente la documentación del método Handler.post ():

Hace que Runnable r se agregue a la cola de mensajes. El ejecutable se ejecutará en el subproceso al que se adjunta este controlador.

Por lo tanto, los ejemplos proporcionados por @ alex2k8, aunque funcionan correctamente, no son lo mismo. En el caso, donde se Handler.post() , no se crean nuevos subprocesos . Usted acaba de publicar Runnable en el hilo con Handler para ser ejecutado por EDT . Después de eso, EDT solo ejecuta Runnable.run() , nada más.

Recuerde: Runnable != Thread .

Un ejemplo interesante es que puede ver continuamente un contador / cronómetro funcionando en un hilo separado. También muestra GPS-Location. Mientras que la actividad principal, el subproceso de interfaz de usuario ya está allí.

Extracto:

 try { cnt++; scnt++; now=System.currentTimeMillis(); r=rand.nextInt(6); r++; loc=lm.getLastKnownLocation(best); if(loc!=null) { lat=loc.getLatitude(); lng=loc.getLongitude(); } Thread.sleep(100); handler.sendMessage(handler.obtainMessage()); } catch (InterruptedException e) { Toast.makeText(this, "Error="+e.toString(), Toast.LENGTH_LONG).show(); } 

Para ver el código, mira aquí:

Ejemplo de subproceso que muestra la ubicación del GPS y la hora actual ejecutables junto con el subproceso de la interfaz de usuario de la actividad principal

ahora en Kotlin puedes ejecutar hilos de esta manera:

 class SimpleRunnable: Runnable { public override fun run() { println("${Thread.currentThread()} has run.") } } fun main(args: Array) { val thread = SimpleThread() thread.start() // Will output: Thread[Thread-0,5,main] has run. val runnable = SimpleRunnable() val thread1 = Thread(runnable) thread1.start() // Will output: Thread[Thread-1,5,main] has run }