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?
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
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
tv.append("Hello Word")
costTmillisecondes, après l'affichage 500 fois le délai est de 500 * T millisecondes3. 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");
}
new Handler().postDelayed(new Runnable() {
public void run() {
// do something...
}
}, 100);
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:
schedule
myTimer.cancel()
myTimer.cancel()
avant programmer un nouveau (si myTimer n'est pas null)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
Handler handler=new Handler();
Runnable r = new Runnable(){
public void run() {
tv.append("Hello World");
handler.postDelayed(r, 1000);
}
};
handler.post(r);
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
.
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:
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
}
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)
}
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);
}