Come eseguire un metodo ogni X secondi


114

Sto sviluppando un'applicazione Android 2.3.3 e devo eseguire un metodo ogni X secondi .

In iOS, ho NSTimer , ma in Android non so cosa usare.

Qualcuno mi ha consigliato Handler ; un altro mi consiglia AlarmManager ma non so quale metodo si adatta meglio NSTimer .

Questo è il codice che voglio implementare in 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
];

Ho bisogno di qualcosa che funzioni funzioni NSTimer .

Cosa mi consigliate?


1
Definisci "il migliore". In che modo vuoi che sia il migliore?
Simon Forsberg

Non so quale metodo si adatta meglio a NSTimer.
VansFannel

@VansFannel Quanto tempo vuoi per un intervallo?
FoamyGuy

Ho aggiornato la domanda con i dettagli su ciò che sto cercando di fare.
VansFannel

Questa domanda: stackoverflow.com/questions/6242268/… , è simile a questa e ha un'ottima risposta.
VansFannel

Risposte:


168

Questo dipende davvero da quanto tempo occorre per eseguire la funzione.

Se è => 10 minuti → Vorrei andare 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();
}

E poi ricevi queste trasmissioni tramite il ricevitore di trasmissione. Si noti che questo dovrà essere registrato ether nel manifest dell'applicazione o tramite il context.registerReceiver(receiver,filter);metodo. Per ulteriori informazioni sui ricevitori di trasmissione, fare riferimento ai documenti ufficiali. Ricevitore di trasmissione .

public class MyReceiver extends BroadcastReceiver{

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

Se è = <10 minuti → Vorrei andare con un gestore.

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

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

3
Perché suggerimenti diversi a seconda del ritardo?
Simon Forsberg

7
Efficienza, nella documentazione di AlarmManager si afferma che non dovrebbe essere utilizzato per attività ripetitive a piccoli intervalli.
Jug6ernaut

9
@ SimonAndréForsberg nei documenti di AlarmManager afferma che Handler è il metodo preferito e più efficiente da utilizzare per i tick brevi: "Nota: Alarm Manager è inteso per i casi in cui si desidera che il codice dell'applicazione venga eseguito in un momento specifico, anche se l'applicazione non è attualmente in esecuzione. Per le normali operazioni di temporizzazione (tick, timeout, ecc.) è più facile e molto più efficiente utilizzare Handler. "
FoamyGuy

Tuttavia, ho bisogno di eseguire un metodo nella stessa attività che ha avviato AlarmManager. Come lo posso fare?
VansFannel

2
@ahmadalibaloch dall'interno del eseguibile che puoi fare h.removeCallbacks(this);, altrimenti devi mantenere un riferimento al eseguibile per poterlo rimuovere. Se si desidera il secondo, il metodo pubblicato qui potrebbe non essere il percorso migliore.
Jug6ernaut


69

Puoi provare questo codice per chiamare il gestore ogni 15 secondi tramite onResume () e interromperlo quando l'attività non è visibile, tramite 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
Questo è quello che stavo cercando. Perfetto.
viper

3
questa è la risposta perfetta!
Riddhi

Spot on! L'utilizzo per il controllo della scheda selezionata corrente di MainActivitys in TabLayout corrisponde a questo frammento e, in caso contrario, interrompe il lavoro, poiché onPause () non riesce quando qualsiasi scheda selezionata di TabLayout su entrambi i lati di questa scheda selezionata
BENN1TH

Perfetto. Questo era quello che stavo cercando :) 1 domanda, posso chiamare questo metodo da un'altra attività. O se ascolto questa attività questo oggetto verrà distrutto? Cosa succede se creo un gestore statico ed eseguibile. È possibile?
hyperCoder

17

Se hai familiarità con RxJava, puoi usare Observable.interval (), che è abbastanza pulito.

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
                }
            });

Lo svantaggio di questo è che devi progettare il polling dei tuoi dati in un modo diverso. Tuttavia, ci sono molti vantaggi nel modo di programmazione reattiva:

  1. Invece di controllare i dati tramite una richiamata, crei un flusso di dati a cui ti iscrivi. Questo separa la preoccupazione della logica di "polling dei dati" e della logica di "compilazione dell'interfaccia utente con i dati" in modo da non mescolare il codice della "sorgente dati" e il codice dell'interfaccia utente.
  2. Con RxAndroid, puoi gestire i thread in sole 2 righe di codice.

    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

Si prega di controllare RxJava. Ha un'elevata curva di apprendimento ma renderà la gestione delle chiamate asincrone in Android molto più semplice e pulita.


4

Con Kotlin, ora possiamo creare una funzione generica per questo!

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

E per usare, basta fare:

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
Non inserire solo il codice di risposta. Si prega di modificare la tua risposta e aggiungere qualche spiegazione.
Shashanth

2

Qui ho usato ripetutamente un thread in onCreate () un'attività, il timer non consente tutto in alcuni casi Thread è la soluzione

     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();

In caso fosse necessario, può essere fermato da

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

per favore descrivi la situazione in cui la mia risposta non funzionerà
Umar Ata

Ciao Umar. Avevo bisogno di un cerchio per tutto il tempo in cui l'app è attiva, Handler ha reso viva la ripetizione mentre l'attività è viva, ma ho bisogno del cerchio mentre potevo visitare anche altre attività. Quindi il filo è la soluzione in questo modo sicuro che abbia anche la sua lotta.
Sam

1

Qui potrebbe essere una risposta utile per il tuo problema utilizzando Rx Java e Rx Android .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.