Cómo ejecutar un método cada X segundos


114

Estoy desarrollando una aplicación para Android 2.3.3 y necesito ejecutar un método cada X segundos .

En iOS, tengo NSTimer , pero en Android no sé qué usar.

Alguien me ha recomendado Handler ; otro me recomendó AlarmManager pero no sé qué método encaja mejor con NSTimer .

Este es el código que quiero implementar en Android:

timer2 = [
    NSTimer scheduledTimerWithTimeInterval:(1.0f/20.0f)
    target:self
    selector:@selector(loopTask)
    userInfo:nil
    repeats:YES
];

timer1 = [
    NSTimer scheduledTimerWithTimeInterval:(1.0f/4.0f)
    target:self
    selector:@selector(isFree)
    userInfo:nil
    repeats:YES
];

Necesito algo que funcione como NSTimer .

¿Qué me recomiendas?


1
Defina "el mejor". ¿De qué manera quieres que sea el mejor?
Simon Forsberg

No sé qué método encaja mejor con NSTimer.
VansFannel

@VansFannel ¿Cuánto tiempo quieres de intervalo?
FoamyGuy

Actualicé la pregunta con detalles sobre lo que estoy tratando de hacer.
VansFannel

Esta pregunta: stackoverflow.com/questions/6242268/… , es similar a esta y tiene una gran respuesta.
VansFannel

Respuestas:


168

Esto realmente depende de cuánto tiempo necesite para ejecutar la función.

Si es => 10 minutos → iría con Alarm Manager.

// Some time when you want to run
Date when = new Date(System.currentTimeMillis());    

try{
   Intent someIntent = new Intent(someContext,MyReceiver.class); // intent to be launched

   // note this could be getActivity if you want to launch an activity
   PendingIntent pendingIntent = PendingIntent.getBroadcast(
        context, 
        0, // id, optional
        someIntent, // intent to launch
        PendingIntent.FLAG_CANCEL_CURRENT); // PendintIntent flag

   AlarmManager alarms = (AlarmManager) context.getSystemService(
        Context.ALARM_SERVICE);

   alarms.setRepeating(AlarmManager.RTC_WAKEUP,
        when.getTime(),
        AlarmManager.INTERVAL_FIFTEEN_MINUTES,
        pendingIntent); 

}catch(Exception e){
   e.printStackTrace();
}

Y luego recibe estas transmisiones a través del receptor de transmisión. Tenga en cuenta que deberá registrarlo en el manifiesto de su aplicación o mediante el context.registerReceiver(receiver,filter);método. Para obtener más información sobre los receptores de transmisión, consulte los documentos oficiales. Receptor de difusión .

public class MyReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) 
    {
         //do stuffs
    }
}

Si es = <10 minutos → iría con un Handler.

Handler handler = new Handler();
int delay = 1000; //milliseconds

handler.postDelayed(new Runnable(){
    public void run(){
        //do something
        handler.postDelayed(this, delay);
    }
}, delay);

3
¿Por qué diferentes sugerencias según el tiempo de retraso?
Simon Forsberg

7
Eficiencia, en los documentos de AlarmManager se indica que no debe usarse para ninguna tarea repetitiva de intervalos pequeños.
Jug6ernaut

9
@ SimonAndréForsberg en los documentos de AlarmManager indica que Handler es el método preferido y más eficiente para usar con ticks cortos: "Nota: El Administrador de alarmas está diseñado para casos en los que desea que el código de su aplicación se ejecute en un momento específico, incluso si su la aplicación no se está ejecutando actualmente. Para las operaciones de temporización normales (ticks, tiempos de espera, etc.) es más fácil y mucho más eficiente usar Handler ".
FoamyGuy

Pero, necesito ejecutar un método en la misma actividad que ha iniciado AlarmManager. ¿Cómo puedo hacer eso?
VansFannel

2
@ahmadalibaloch desde dentro del ejecutable que puede hacer h.removeCallbacks(this);, de lo contrario, debe mantener una referencia al ejecutable para poder eliminarlo. Si se desea el segundo, el método publicado aquí podría no ser su mejor ruta.
Jug6ernaut


69

Puede probar este código para llamar al controlador cada 15 segundos a través de onResume () y detenerlo cuando la actividad no sea visible, a través de onPause ().

Handler handler = new Handler();
Runnable runnable;
int delay = 15*1000; //Delay for 15 seconds.  One second = 1000 milliseconds.


@Override
protected void onResume() {
   //start handler as activity become visible

    handler.postDelayed( runnable = new Runnable() {
        public void run() {
            //do something

            handler.postDelayed(runnable, delay);
        }
    }, delay);

    super.onResume();
}

// If onPause() is not included the threads will double up when you 
// reload the activity 

@Override
protected void onPause() {
    handler.removeCallbacks(runnable); //stop handler when activity not visible
    super.onPause();
}

5
Esto es lo que estaba buscando. Perfecto.
víbora

3
esa es la respuesta perfecta!
Riddhi

¡Correcto! Usar para verificar la pestaña seleccionada actual de MainActivitys en TabLayout coincide con este fragmento y, si no deja de funcionar, ya que onPause () falla cuando cualquier TabLayout seleccionó pestañas a ambos lados de esta pestaña seleccionada
BENN1TH

Perfecto. Esto era lo que estaba buscando :) 1 pregunta, ¿puedo llamar a este método desde otra actividad? ¿O si dejo esta actividad, este objeto será destruido? ¿Qué pasa si creo un controlador estático y ejecutable. ¿Es eso posible?
hyperCoder

17

Si está familiarizado con RxJava, puede usar Observable.interval (), que es bastante bueno.

Observable.interval(60, TimeUnits.SECONDS)
          .flatMap(new Function<Long, ObservableSource<String>>() {
                @Override
                public ObservableSource<String> apply(@NonNull Long aLong) throws Exception {
                    return getDataObservable(); //Where you pull your data
                }
            });

La desventaja de esto es que debe diseñar el sondeo de sus datos de una manera diferente. Sin embargo, hay muchos beneficios en la forma de programación reactiva:

  1. En lugar de controlar sus datos a través de una devolución de llamada, crea un flujo de datos al que se suscribe. Esto separa la preocupación de la lógica de "sondeo de datos" y la lógica de "llenar la interfaz de usuario con sus datos" para que no mezcle su código de "fuente de datos" y su código de interfaz de usuario.
  2. Con RxAndroid, puede manejar subprocesos en solo 2 líneas de código.

    Observable.interval(60, TimeUnits.SECONDS)
          .flatMap(...) // polling data code
          .subscribeOn(Schedulers.newThread()) // poll data on a background thread
          .observeOn(AndroidSchedulers.mainThread()) // populate UI on main thread
          .subscribe(...); // your UI code

Consulte RxJava. Tiene una curva de aprendizaje alta, pero hará que el manejo de llamadas asincrónicas en Android sea mucho más fácil y limpio.


4

¡Con Kotlin, ahora podemos hacer una función genérica para esto!

object RepeatHelper {
    fun repeatDelayed(delay: Long, todo: () -> Unit) {
        val handler = Handler()
        handler.postDelayed(object : Runnable {
            override fun run() {
                todo()
                handler.postDelayed(this, delay)
            }
        }, delay)
    }
}

Y para usar, simplemente haz:

val delay = 1000L
RepeatHelper.repeatDelayed(delay) {
    myRepeatedFunction()
}

3
    new CountDownTimer(120000, 1000) {

        public void onTick(long millisUntilFinished) {
            txtcounter.setText(" " + millisUntilFinished / 1000);

        }

        public void onFinish() {

            txtcounter.setText(" TimeOut  ");
            Main2Activity.ShowPayment = false;
            EventBus.getDefault().post("go-main");

        }

    }.start();

4
No publique solo el código de respuesta. Por favor, editar su respuesta y añadir un poco de explicación.
Shashanth

2

Aquí utilicé un hilo en onCreate () una actividad repetidamente, el temporizador no permite todo en algunos casos el hilo es la solución

     Thread t = new Thread() {
        @Override
        public void run() {
            while (!isInterrupted()) {
                try {
                    Thread.sleep(10000);  //1000ms = 1 sec
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {

                            SharedPreferences mPrefs = getSharedPreferences("sam", MODE_PRIVATE);
                            Gson gson = new Gson();
                            String json = mPrefs.getString("chat_list", "");
                            GelenMesajlar model = gson.fromJson(json, GelenMesajlar.class);
                            String sam = "";

                            ChatAdapter adapter = new ChatAdapter(Chat.this, model.getData());
                            listview.setAdapter(adapter);
                           // listview.setStackFromBottom(true);
                          //  Util.showMessage(Chat.this,"Merhabalar");
                        }
                    });

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    t.start();

En caso de que sea necesario, puede ser detenido por

@Override
protected void onDestroy() {
    super.onDestroy();
    Thread.interrupted();
    //t.interrupted();
}

por favor describa la situación cuando mi respuesta no funcionará
Umar Ata

Hola Umar. Necesitaba un círculo todo el tiempo que la aplicación está viva, Handler hizo que la repetición estuviera viva mientras la actividad está viva, pero necesito el círculo mientras pude visitar otras actividades también. Entonces el hilo es la solución de esta manera seguro que también tiene su lucha.
Sam

1

Aquí tal vez una respuesta útil para su problema al usar Rx Java & Rx Android .

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.