¿Cómo ejecutar un hilo ejecutable 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 corro esta aplicación el texto se muestra solo una vez. ¿Por qué?

Author: Ravindra babu, 2009-12-17

10 answers

La solución simple para su 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 el corredor 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 solo como un comando que se puede enviar a la cola de mensajes para su ejecución, y handler como solo un objeto auxiliar utilizado para enviar ese comando.

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

 470
Author: alex2k8,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-24 15:50:50

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, asuma tv.append("Hello Word") costo T milisegundos, después de la visualización 500 tiempos de retraso el tiempo es 500 * T milisegundos
  • Se incrementará retrasado cuando se ejecute mucho tiempo

3. Solución

Para evitar que Solo cambie el orden de postDelayed (), para evitar retrasado:

public void run() {
    handler.postDelayed(this, 1000);
    tv.append("Hello World");
}
 39
Author: NguyenDat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-15 13:47:02
new Handler().postDelayed(new Runnable() {
    public void run() {
        // do something...              
    }
}, 100);
 32
Author: user2212515,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-23 19:25:38

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

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 Timer tiene pocas ventajas:

  • El retraso inicial y el intervalo se pueden especificar fácilmente en los argumentos de la función schedule
  • El temporizador se puede detener simplemente llamando a myTimer.cancel()
  • Si desea tener un solo subproceso en ejecución, recuerde llamar myTimer.cancel() antes de programar una nueva (si myTimer no es null)
 23
Author: iTech,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-15 15:45:14

Para repetir la tarea se puede utilizar

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á por primera vez después de medio segundo(500) y se repetirá después de cada segundo(1000)

Donde

Task siendo el método a ejecutar

Después de el tiempo para la ejecución inicial

(intervalo el tiempo para repetir la ejecución)

En segundo lugar

Y también puedes utilice CountDownTimer si desea ejecutar una tarea varias 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 llamarlo 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 
 22
Author: Xar E Ahmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-17 05:46:27
Handler handler=new Handler();
Runnable r = new Runnable(){
    public void run() {
        tv.append("Hello World");                       
        handler.postDelayed(r, 1000);
    }
}; 
handler.post(r);
 15
Author: singh arjun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-21 18:25:16

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

Hace que la r ejecutable se agregue a la cola de mensajes. El runnable se ejecutará en el hilo al que está unido este controlador.

Así que los ejemplos proporcionados por @alex2k8, aunque funcionan correctamente, no son los mismos. En caso de que se use Handler.post(), no se crean nuevos hilos. 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.

Recuerda: Runnable != Thread.

 3
Author: Damian Walczak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-08 21:44:59

Un ejemplo interesante es que puedes ver continuamente un contador/cronómetro corriendo en subprocesos separados. También muestra la ubicación GPS. Mientras que el hilo de la interfaz de usuario de la actividad principal 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 ver aquí:

Ejemplo de subproceso que muestra la Ubicación GPS y la Hora Actual ejecutable junto con la Interfaz de Usuario de la actividad principal Subproceso

 1
Author: Animesh Shrivastav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-25 16:46:02

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<String>) {
    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
}
 0
Author: Andreh Abboud,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-25 18:25:11

Kotlin

private lateinit var runnable: Runnable
override fun onCreate(savedInstanceState: Bundle?) {
    val handler = Handler()
    runnable = Runnable {
        handler.postDelayed(runnable, 2000)
    }
    handler.postDelayed(runnable, 2000)
}

Java

Runnable runnable;
Handler handler;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    handler = new Handler();
    runnable = new Runnable() {
        @Override
        public void run() {
            handler.postDelayed(this, 1000);
        }
    };
    handler.postDelayed(runnable, 1000);
}
 0
Author: Khemraj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-21 13:29:45