web-dev-qa-db-fra.com

Comment exécuter un thread Runnable sous Android à des intervalles définis?

J'ai développé une application pour afficher du texte à des intervalles définis sur l'écran de l'émulateur Android. J'utilise la classe Handler. Voici un extrait de mon code:

handler = new Handler();
Runnable r = new Runnable() {
    public void run() {
        tv.append("Hello World");               
    }
};
handler.postDelayed(r, 1000);

Lorsque je lance cette application, le texte ne s'affiche qu'une fois. Pourquoi?

306
Rajapandian

La solution simple à votre exemple est la suivante:

handler = new Handler();

final Runnable r = new Runnable() {
    public void run() {
        tv.append("Hello World");
        handler.postDelayed(this, 1000);
    }
};

handler.postDelayed(r, 1000);

Ou nous pouvons utiliser un fil normal par exemple (avec Runner original):

Thread thread = new Thread() {
    @Override
    public void run() {
        try {
            while(true) {
                sleep(1000);
                handler.post(this);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};

thread.start();

Vous pouvez considérer votre objet exécutable comme une commande pouvant être envoyée à la file d'attente de messages pour exécution et le gestionnaire comme un simple objet d'assistance utilisé pour envoyer cette commande.

Plus de détails sont ici http://developer.Android.com/reference/Android/os/Handler.html

489
alex2k8

Je pense que peut améliorer la première solution de Alex2k8 pour la mise à jour correcte chaque seconde

1.Code d'origine:

public void run() {
    tv.append("Hello World");
    handler.postDelayed(this, 1000);
}

2.Analyse

  • Dans le coût ci-dessus, supposons que tv.append("Hello Word") costTmillisecondes, après l'affichage 500 fois le délai est de 500 * T millisecondes
  • Il va augmenter retardé quand courir longtemps

3. Solution

Pour éviter cela, il suffit de changer l'ordre de postDelayed (), afin d'éviter les retards:

public void run() {
    handler.postDelayed(this, 1000);
    tv.append("Hello World");
}
40
NguyenDat
new Handler().postDelayed(new Runnable() {
    public void run() {
        // do something...              
    }
}, 100);
35
user2212515

Je pense que pour ce cas typique, c’est-à-dire pour exécuter quelque chose avec un intervalle fixe, Timer est plus approprié. Voici un exemple simple:

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

Utiliser Timer a peu d'avantages:

  • Le délai initial et l'intervalle peuvent être facilement spécifiés dans les arguments de la fonction schedule
  • Le chronomètre peut être arrêté en appelant simplement myTimer.cancel()
  • Si vous voulez avoir un seul thread en cours d'exécution, rappelez-vous d'appeler myTimer.cancel() avant programmer un nouveau (si myTimer n'est pas null)
23
iTech

Pour répéter la tâche, vous pouvez utiliser

new Timer().scheduleAtFixedRate(task, runAfterADelayForFirstTime, repeaingTimeInterval);

appelle comme ça 

new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {

            }
        },500,1000);

Le code ci-dessus s’exécutera pour la première fois après une demi-seconde (500) et se répétera après chaque seconde (1000)

Où 

tâche étant la méthode à exécuter

après l'heure de la première exécution 

( intervalle heure de répétition de l'exécution)

Deuxièmement

Et vous pouvez également utiliser CountDownTimer si vous voulez exécuter un nombre de fois de tâche.

    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

Et vous pouvez aussi le faire avec runnable. créer une méthode exécutable comme 

Runnable runnable = new Runnable()
    {
        @Override
        public void run()
        {

        }
    };

Et appelez cela de ces deux manières

new Handler().postDelayed(runnable, 500 );//where 500 is delayMillis  // to work on mainThread

OU

new Thread(runnable).start();//to work in Background 
22
Xar E Ahmer
Handler handler=new Handler();
Runnable r = new Runnable(){
    public void run() {
        tv.append("Hello World");                       
        handler.postDelayed(r, 1000);
    }
}; 
handler.post(r);
16
singh arjun

Si je comprends bien la documentation de la méthode Handler.post ():

Rend le Runnable r être ajouté à la file de messages. Le runnable sera exécuté sur le thread auquel ce gestionnaire est attaché.

Ainsi, les exemples fournis par @ alex2k8, même s'ils fonctionnent correctement, ne sont pas identiques . Dans le cas où Handler.post() est utilisé, aucun nouveau thread n'est créé. Vous venez de poster Runnable sur le thread avec Handler à exécuter par EDT . Après cela, EDT exécute uniquement Runnable.run(), rien d'autre.

Rappelez-vous: Runnable != Thread.

3
Damian Walczak

Un exemple intéressant est que vous pouvez voir en permanence un compteur/chronomètre tournant dans un fil séparé. Affichage également de la localisation GPS. Alors que l’activité principale, le fil d’interface utilisateur existe déjà.

Extrait:

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

Pour regarder le code, voir ici:

Exemple de fil affichant la position GPS et l'heure actuelle exécutable aux côtés du fil de l'interface utilisateur de l'activité principale

1
Animesh Shrivastav

maintenant, dans Kotlin, vous pouvez exécuter les discussions de cette façon:

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
Andreh Abboud

Kotlin

private lateinit var runnable: Runnable
override fun onCreate(savedInstanceState: Bundle?) {
    val handler = Handler()
    runnable = Runnable {
        // do your work
        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() {
            // do your work
            handler.postDelayed(this, 1000);
        }
    };
    handler.postDelayed(runnable, 1000);
}
0
Khemraj