Como executar um tópico executável em Android em intervalos definidos?
desenvolvi uma aplicação para mostrar algum texto a intervalos definidos na tela do emulador Android. Estou a usar a classe Handler
. Aqui está um trecho do meu código:
handler = new Handler();
Runnable r = new Runnable() {
public void run() {
tv.append("Hello World");
}
};
handler.postDelayed(r, 1000);
Quando eu executar esta aplicação o texto é mostrado apenas uma vez. Por quê?
10 answers
A solução simples para o seu exemplo é:
handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
tv.append("Hello World");
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(r, 1000);
Ou podemos usar o tópico normal, por exemplo (com o corredor original) :
Thread thread = new Thread() {
@Override
public void run() {
try {
while(true) {
sleep(1000);
handler.post(this);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
Você pode considerar o seu objecto executável como um comando que pode ser enviado para a fila de mensagens para execução, e o handler como apenas um objecto auxiliar usado para enviar esse comando.
Mais detalhes estão aqui http://developer.android.com/reference/android/os/Handler.html
Eu acho que pode melhorar a primeira solução de Alex2k8 para atualizar correto a cada segundo
1.Código Original:
public void run() {
tv.append("Hello World");
handler.postDelayed(this, 1000);
}
2.Análise
- no custo acima, assumir
tv.append("Hello Word")
o custo T milisegundos, após visualização 500 Os tempos de atraso são 500 * T milisegundos - irá aumentar com atraso quando durar muito tempo
3. Solução
Para evitar que apenas mude a ordem de postDelayed (), para evitar atrasado:
public void run() {
handler.postDelayed(this, 1000);
tv.append("Hello World");
}
new Handler().postDelayed(new Runnable() {
public void run() {
// do something...
}
}, 100);
Eu acredito que para este caso típico, isto é, para executar algo com um intervalo fixo, Timer
é mais apropriado. Aqui está um exemplo simples:
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
Usar Timer
tem poucas vantagens:
- o atraso inicial e o intervalo podem ser facilmente especificados nos argumentos da função
schedule
- O temporizador pode ser parado simplesmente chamando
myTimer.cancel()
Se quiser ter apenas um tópico a correr, lembre-se de ligar.
myTimer.cancel()
antes de marcar um novo (se o meu tempo for não nulo)
Para repetir a tarefa você pode usar
new Timer().scheduleAtFixedRate(task, runAfterADelayForFirstTime, repeaingTimeInterval);
Chama-lhe como
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
}
},500,1000);
O código acima será executado pela primeira vez após meio segundo (500) e repetir-se-á após cada segundo(1000)
Onde
Tarefa sendo o método a ser executado
Após o tempo para a execução inicial
(intervalo {[9] } o tempo para repetir a execução)
Em Segundo Lugar
E você também pode usar CountDownTimer Se quiser executar uma tarefa várias vezes.
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
E também podes fazê-lo com runnable. criar um método executável como
Runnable runnable = new Runnable()
{
@Override
public void run()
{
}
};
E chama-o de ambas as maneiras
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);
Se bem entendi a documentação do Handler.Método post ():
Faz com que o R executável seja adicionado à fila de mensagens. O executável será executado no tópico ao qual este manipulador Está ligado.
Então os exemplos fornecidos por @alex2k8, embora estejam funcionando corretamente, não são os mesmos.
No caso em que Handler.post()
é usado, não são criados novos tópicos. Basta postar Runnable
no tópico com Handler
para ser executado por EDT .
Depois disso, O EDT apenas executa Runnable.run()
, nada mais.
Runnable != Thread
.
Um exemplo interessante é que você pode ver continuamente um contador/relógio de parada rodando em um tópico separado. Também mostra a localização do GPS. Enquanto o tópico principal da Interface de usuário de atividade já está lá.
Excerto:
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();
}
Para ver o código veja aqui:
Agora no Kotlin você pode executar os tópicos desta forma:
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
}
Kotlin
private lateinit var runnable: Runnable
override fun onCreate(savedInstanceState: Bundle?) {
val handler = Handler()
runnable = Runnable {
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() {
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(runnable, 1000);
}