Comment exécuter une méthode toutes les X secondes

114

Je développe une application Android 2.3.3 et je dois exécuter une méthode toutes les X secondes .

Sous iOS, j'ai NSTimer , mais sous Android, je ne sais pas quoi utiliser.

Quelqu'un m'a recommandé Handler ; un autre me recommande AlarmManager mais je ne sais pas quelle méthode convient le mieux à NSTimer .

Voici le code que je souhaite implémenter dans 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
];

J'ai besoin de quelque chose qui fonctionne comme NSTimer .

Que me recommandez-vous?

VansFannel
la source
1
Définissez "le meilleur". De quelle manière voulez-vous que ce soit le meilleur?
Simon Forsberg du
Je ne sais pas quelle méthode convient le mieux à NSTimer.
VansFannel du
@VansFannel Combien de temps d'intervalle voulez-vous?
FoamyGuy
J'ai mis à jour la question avec des détails sur ce que j'essaie de faire.
VansFannel du
Cette question: stackoverflow.com/questions/6242268/… , est similaire à celle-ci et a une excellente réponse.
VansFannel

Réponses:

168

Cela dépend vraiment de l'intervalle dont vous avez besoin pour exécuter la fonction.

Si c'est => 10 minutes → j'irais avec 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();
}

Et puis vous recevez ces émissions via un récepteur de diffusion. Notez que cela devra être enregistré ether dans le manifeste de votre application ou via la context.registerReceiver(receiver,filter);méthode. Pour plus d'informations sur les récepteurs de diffusion, veuillez vous référer à la documentation officielle. Récepteur de diffusion .

public class MyReceiver extends BroadcastReceiver{

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

Si c'est = <10minutes → j'irais avec un Handler.

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

handler.postDelayed(new Runnable(){
    public void run(){
        //do something
        handler.postDelayed(this, delay);
    }
}, delay);
Jug6ernaut
la source
3
Pourquoi des suggestions différentes en fonction du délai?
Simon Forsberg
7
Efficacité, dans la documentation d'AlarmManager, il indique qu'il ne doit pas être utilisé pour une tâche répétitive à petit intervalle.
Jug6ernaut
9
@ SimonAndréForsberg dans la documentation AlarmManager indique que Handler est la méthode préférée et la plus efficace à utiliser pour les ticks courts: "Remarque: Le gestionnaire d'alarme est destiné aux cas où vous souhaitez que votre code d'application s'exécute à un moment précis, même si votre l'application n'est pas en cours d'exécution. Pour les opérations de chronométrage normales (ticks, délais, etc.), il est plus facile et beaucoup plus efficace d'utiliser Handler. "
FoamyGuy
Mais, j'ai besoin d'exécuter une méthode dans la même activité qui a lancé AlarmManager. Comment puis je faire ça?
VansFannel du
2
@ahmadalibaloch depuis le runnable, vous pouvez le faire h.removeCallbacks(this);, sinon vous devez maintenir une référence au runnable pour pouvoir le supprimer. Si la seconde est souhaitée, la méthode indiquée ici n'est peut-être pas votre meilleur itinéraire.
Jug6ernaut
101

Utilisez Timer pour chaque seconde ...

new Timer().scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        //your method
    }
}, 0, 1000);//put here time 1000 milliseconds=1 second
Samir Mangroliya
la source
J'ai mis à jour la question avec des détails sur ce que j'essaie de faire.
VansFannel du
4
N'utilisez pas Timer ( mopri.de/2010/timertask-bad-do-it-the-android-way-use-a-handler ), utilisez Handler ou ScheduledThreadPoolExecutor.
AppiDevo
69

Vous pouvez essayer ce code pour appeler le gestionnaire toutes les 15 secondes via onResume () et l'arrêter lorsque l'activité n'est pas visible, via 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();
}
Umar Ata
la source
5
C'est ce que je cherchais. Parfait.
viper
3
c'est la réponse parfaite!
Riddhi
Sur place! L'utilisation pour vérifier l'onglet sélectionné actuel de MainActivitys dans TabLayout correspond à ce fragment et sinon, arrêtez le travail - car onPause () échoue lorsque l'un des onglets sélectionnés de TabLayout de chaque côté de cet onglet sélectionné
BENN1TH
parfait. C'est ce que je cherchais :) 1 question, puis-je appeler cette méthode à partir d'une autre activité. Ou si j'avance cette activité, cet objet sera détruit? Et si je crée un gestionnaire statique et exécutable. Est-ce possible?
hyperCoder
17

Si vous êtes familier avec RxJava, vous pouvez utiliser Observable.interval (), ce qui est assez sympa.

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

L'inconvénient est que vous devez l'architecte en interrogeant vos données d'une manière différente. Cependant, la méthode de programmation réactive présente de nombreux avantages:

  1. Au lieu de contrôler vos données via un rappel, vous créez un flux de données auquel vous vous abonnez. Cela sépare le souci de la logique «d'interrogation des données» et de la logique «de remplissage de l'interface utilisateur avec vos données» afin de ne pas mélanger votre code «source de données» et votre code d'interface utilisateur.
  2. Avec RxAndroid, vous pouvez gérer les threads en seulement 2 lignes de code.

    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

Veuillez vérifier RxJava. Il a une courbe d'apprentissage élevée, mais cela rendra la gestion des appels asynchrones sous Android beaucoup plus facile et plus propre.

wdina
la source
4

Avec Kotlin, nous pouvons maintenant créer une fonction générique pour cela!

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

Et pour l'utiliser, il suffit de faire:

val delay = 1000L
RepeatHelper.repeatDelayed(delay) {
    myRepeatedFunction()
}
Luke
la source
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();
Behzad F94
la source
4
Ne postez pas le code uniquement pour répondre. Veuillez modifier votre réponse et ajouter quelques explications.
Shashanth
2

Ici, j'ai utilisé un thread dans onCreate () an Activity à plusieurs reprises, la minuterie ne permet pas tout dans certains cas Thread est la solution

     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 cas de besoin, il peut être arrêté par

@Override
protected void onDestroy() {
    super.onDestroy();
    Thread.interrupted();
    //t.interrupted();
}
Sam
la source
Veuillez décrire la situation où ma réponse ne fonctionnera pas
Umar Ata
Bonjour Umar. J'avais besoin d'un cercle pendant tout le temps où l'application est vivante, Handler a rendu la répétition vivante pendant que l'activité est vivante mais j'ai besoin du cercle pendant que je pouvais aussi visiter d'autres activités. Le fil est donc une solution de cette manière, sûr qu'il a aussi sa lutte.
Sam le
1

Voici peut-être une réponse utile à votre problème en utilisant Rx Java & Rx Android .

Sepehr
la source