Repita una tarea con un retraso de tiempo?

Tengo una variable en mi código que dice que es “estado”.

Quiero mostrar algo de texto en la aplicación dependiendo de este valor de variable. Esto tiene que hacerse con un retraso de tiempo específico.

Es como,

  • Comprobar el valor de la variable de estado

  • Mostrar un texto

  • Espera 10 segundos

  • Comprobar el valor de la variable de estado

  • Mostrar un texto

  • Espere 15 segundos

y así. El retraso de tiempo puede variar y se establece una vez que se muestra el texto.

He intentado Thread.sleep(time delay) y falló. ¿Alguna mejor manera de hacer esto?

Debería usar la función postDelayed Handler para este propósito. Ejecutará el código con la demora especificada en la secuencia de la interfaz de usuario principal, por lo que podrá actualizar los controles de la interfaz de usuario.

 private int mInterval = 5000; // 5 seconds by default, can be changed later private Handler mHandler; @Override protected void onCreate(Bundle bundle) { // your code here mHandler = new Handler(); startRepeatingTask(); } @Override public void onDestroy() { super.onDestroy(); stopRepeatingTask(); } Runnable mStatusChecker = new Runnable() { @Override public void run() { try { updateStatus(); //this function can change value of mInterval. } finally { // 100% guarantee that this always happens, even if // your update method throws an exception mHandler.postDelayed(mStatusChecker, mInterval); } } }; void startRepeatingTask() { mStatusChecker.run(); } void stopRepeatingTask() { mHandler.removeCallbacks(mStatusChecker); } 

Para cualquier persona interesada, he aquí una clase que he creado utilizando el código de inazaruk que crea todo lo que necesito (lo llamé UIUpdater porque lo uso para actualizar periódicamente la interfaz de usuario, pero puede llamarlo como quiera):

 import android.os.Handler; /** * A class used to perform periodical updates, * specified inside a runnable object. An update interval * may be specified (otherwise, the class will perform the * update every 2 seconds). * * @author Carlos Simões */ public class UIUpdater { // Create a Handler that uses the Main Looper to run in private Handler mHandler = new Handler(Looper.getMainLooper()); private Runnable mStatusChecker; private int UPDATE_INTERVAL = 2000; /** * Creates an UIUpdater object, that can be used to * perform UIUpdates on a specified time interval. * * @param uiUpdater A runnable containing the update routine. */ public UIUpdater(final Runnable uiUpdater) { mStatusChecker = new Runnable() { @Override public void run() { // Run the passed runnable uiUpdater.run(); // Re-run it after the update interval mHandler.postDelayed(this, UPDATE_INTERVAL); } }; } /** * The same as the default constructor, but specifying the * intended update interval. * * @param uiUpdater A runnable containing the update routine. * @param interval The interval over which the routine * should run (milliseconds). */ public UIUpdater(Runnable uiUpdater, int interval){ UPDATE_INTERVAL = interval; this(uiUpdater); } /** * Starts the periodical update routine (mStatusChecker * adds the callback to the handler). */ public synchronized void startUpdates(){ mStatusChecker.run(); } /** * Stops the periodical update routine from running, * by removing the callback. */ public synchronized void stopUpdates(){ mHandler.removeCallbacks(mStatusChecker); } } 

Luego puedes crear un objeto UIUpdater dentro de tu clase y usarlo así:

 ... mUIUpdater = new UIUpdater(new Runnable() { @Override public void run() { // do stuff ... } }); // Start updates mUIUpdater.startUpdates(); // Stop updates mUIUpdater.stopUpdates(); ... 

Si desea utilizar esto como un actualizador de actividad, coloque la llamada de inicio dentro del método onResume () y la llamada de detención dentro de onPause (), de modo que las actualizaciones comiencen y dejen de acuerdo con la visibilidad de la actividad.

Creo que el nuevo calor es usar un ScheduledThreadPoolExecutor . Al igual que:

 private final ScheduledThreadPoolExecutor executor_ = new ScheduledThreadPoolExecutor(1); this.executor_.scheduleWithFixedDelay(new Runnable() { @Override public void run() { update(); } }, 0L, kPeriod, kTimeUnit); 

Timer funciona bien. Aquí, uso Timer para buscar texto después de 1.5 sy actualizar la IU. Espero que ayude.

 private Timer _timer = new Timer(); _timer.schedule(new TimerTask() { @Override public void run() { // use runOnUiThread(Runnable action) runOnUiThread(new Runnable() { @Override public void run() { search(); } }); } }, timeInterval); 

El temporizador es otra forma de hacer su trabajo, pero asegúrese de agregar runOnUiThread si está trabajando con UI.

  import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Timer; import java.util.TimerTask; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.TextView; import android.app.Activity; public class MainActivity extends Activity { CheckBox optSingleShot; Button btnStart, btnCancel; TextView textCounter; Timer timer; MyTimerTask myTimerTask; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); optSingleShot = (CheckBox)findViewById(R.id.singleshot); btnStart = (Button)findViewById(R.id.start); btnCancel = (Button)findViewById(R.id.cancel); textCounter = (TextView)findViewById(R.id.counter); btnStart.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { if(timer != null){ timer.cancel(); } //re-schedule timer here //otherwise, IllegalStateException of //"TimerTask is scheduled already" //will be thrown timer = new Timer(); myTimerTask = new MyTimerTask(); if(optSingleShot.isChecked()){ //singleshot delay 1000 ms timer.schedule(myTimerTask, 1000); }else{ //delay 1000ms, repeat in 5000ms timer.schedule(myTimerTask, 1000, 5000); } }}); btnCancel.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { if (timer!=null){ timer.cancel(); timer = null; } } }); } class MyTimerTask extends TimerTask { @Override public void run() { Calendar calendar = Calendar.getInstance(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a"); final String strDate = simpleDateFormat.format(calendar.getTime()); runOnUiThread(new Runnable(){ @Override public void run() { textCounter.setText(strDate); }}); } } } 

y xml es …

    

Otra forma de usar CountDownTimer

 new CountDownTimer(30000, 1000) { public void onTick(long millisUntilFinished) { mTextField.setText("seconds remaining: " + millisUntilFinished / 1000); } public void onFinish() { mTextField.setText("done!"); } }.start(); 

Programe una cuenta regresiva hasta un momento en el futuro, con notificaciones regulares en intervalos en el camino. Ejemplo de mostrar una cuenta atrás de 30 segundos en un campo de texto:

Para detalles

Puede usar un controlador para publicar código ejecutable. Esta técnica se describe muy bien aquí: https://guides.codepath.com/android/Repeating-Periodic-Tasks

Intenta seguir el ejemplo, ¡funciona!

Utilice [Handler] en el método onCreate () que utiliza el método postDelayed () que hace que Runnable se agregue a la cola de mensajes, para que se ejecute una vez transcurrido el tiempo especificado que es 0 en el ejemplo dado. 1

Consulte este código:


 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //------------------ //------------------ android.os.Handler customHandler = new android.os.Handler(); customHandler.postDelayed(updateTimerThread, 0); } private Runnable updateTimerThread = new Runnable() { public void run() { //write here whaterver you want to repeat customHandler.postDelayed(this, 1000); } }; 

En mi caso, tuve que ejecutar un proceso si una de estas condiciones era verdadera: si se completó un proceso anterior o si ya pasaron 5 segundos. Entonces, hice lo siguiente y funcionó bastante bien:

 private Runnable mStatusChecker; private Handler mHandler; class { method() { mStatusChecker = new Runnable() { int times = 0; @Override public void run() { if (times < 5) { if (process1.isRead()) { executeProcess2(); } else { times++; mHandler.postDelayed(mStatusChecker, 1000); } } else { executeProcess2(); } } }; mHandler = new Handler(); startRepeatingTask(); } void startRepeatingTask() { mStatusChecker.run(); } void stopRepeatingTask() { mHandler.removeCallbacks(mStatusChecker); } } 

Si se lee el proceso1, ejecuta el proceso2. De lo contrario, incrementa la variable veces, y hace que el controlador se ejecute después de un segundo. Mantiene un bucle hasta que se lea el proceso1 o el tiempo sea 5. Cuando el tiempo es 5, significa que pasaron 5 segundos y en cada segundo se ejecuta la cláusula if de process1.isRead ().

Basado en la publicación anterior sobre el ScheduledThreadPoolExecutor , se me ocurrió una utilidad que se ajustaba a mis necesidades (quería lanzar un método cada 3 segundos):

 class MyActivity { private ScheduledThreadPoolExecutor mDialogDaemon; private void initDebugButtons() { Button btnSpawnDialogs = (Button)findViewById(R.id.btn_spawn_dialogs); btnSpawnDialogs.setVisibility(View.VISIBLE); btnSpawnDialogs.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { spawnDialogs(); } }); } private void spawnDialogs() { if (mDialogDaemon != null) { mDialogDaemon.shutdown(); mDialogDaemon = null; } mDialogDaemon = new ScheduledThreadPoolExecutor(1); // This process will execute immediately, then execute every 3 seconds. mDialogDaemon.scheduleAtFixedRate(new Runnable() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { // Do something worthwhile } }); } }, 0L, 3000L, TimeUnit.MILLISECONDS); } } 

Hazlo en la forma de Android con la ayuda de Handler .

Declare una clase Handler interna que no pierda Memory en su clase Activity / Fragment

 /** * Instances of static inner classes do not hold an implicit * reference to their outer class. */ private static class NonLeakyHandler extends Handler { private final WeakReference mActivity; public NonLeakyHandler(FlashActivity activity) { mActivity = new WeakReference(activity); } @Override public void handleMessage(Message msg) { FlashActivity activity = mActivity.get(); if (activity != null) { // ... } } } 

Declare un ejecutable que realizará su tarea repetitiva en su clase Activity / Fragment

  private Runnable repeatativeTaskRunnable = new Runnable() { public void run() { new Handler(getMainLooper()).post(new Runnable() { @Override public void run() { //DO YOUR THINGS } }; 

Inicialice el objeto Handler en su Activity / Fragment (aquí FlashActivity es mi clase de actividad)

 //Task Handler private Handler taskHandler = new NonLeakyHandler(FlashActivity.this); 

Para repetir una tarea después del intervalo de tiempo de reparación

taskHandler.postDelayed (repeatativeTaskRunnable, DELAY_MILLIS);

Para detener la repetición de la tarea

taskHandler .removeCallbacks (repeatativeTaskRunnable);