2015-06-14 20 views
6

Quello che stavo cercando di fare era di diminuire il ritardo del timer ogni volta che il contatore diventa un multiplo di 5. Ma, non appena il codice ha inserito il blocco if, ha smesso di incrementare il timer. Non riesco a capire cosa sta succedendo.Come modificare il ritardo del thread sleep/timer in Android durante il runtime?

Questo è il codice

thread=new Thread(){ 
    public void run(){ 
     try{ 
      if(count%5==0) 
       timre--; 
      else{ 
       //do nothing 
      } 
      //*******PROGRESS UPDATE********// 
      for(t=0;t<=100;t++) { 
       sleep((timre)/100); 
       progress.setProgress(t); 
       t += 1; 
      } 
      //****PROGRESS UPDATE OVER****// 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     finally { 
      finish(); 
     } 
    }//run ends 
};//thread ends 
thread.start();//timer starts 
+0

Puoi mostrare più codice per favore? Dove inizializzi il timer? – Wishmaster

risposta

5

Thread.sleep() non è garantito. Ciò significa che può o non può dormire per la durata desiderata per vari motivi fuori tema per questa domanda.

Se si cerca la rete per "timer in Android" si avrà probabilmente atterrare su questi due: https://developer.android.com/reference/java/util/Timer.html e https://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor.html

Si potrebbe controllare fuori, però, non vorrei usare quelli in quanto forniscono un sacco di altre funzionalità come suggerisce il nome ("ScheduledThreadPoolExecutor"). Non hai bisogno di questo perché è più probabile che venga utilizzato per grandi sistemi con molti thread ecc ...

Se ho capito bene il tuo codice, stai tentando di aggiornare una barra di avanzamento. Per quello che stai cercando di fare ti suggerirei di usare un gestore.Uno dei principali usi di un gestore è quello di pianificare i messaggi e runnables essere eseguito come un certo punto in futuro, come specificato nella documentazione qui: http://developer.android.com/reference/android/os/Handler.html

lo farei in questo modo:

int counter = 0; 
int delayInMs = 5000; // 5 seconds 
Handler timer = new Handler(new Handler.Callback() { 

@Override 
public boolean handleMessage(Message msg) { 
    counter++; 
    // If the counter is mod 5 (or whatever) lower the delay 
    if (counter % 5 == 0) { 
    delayInMs/=100; // Or any other calculation. 
    } 
    // If the counter reaches 100 the counting will not continue. 
    if (counter <= 100) { 
    // If the counter has not reached the condition to stop, the handler 
    // will call the timer again with the modified (or not) delay. 
    timer.sendEmptyMessageDelayed(0, delayInMs); 

    // Change progress 
    updateProgress(counter); 
    } 
    return true; 
} 
}); 
// ... 

// Somwhere in the code to start the counter 
timer.sendEmptyMessageDelayed(0, delayInMs); // starts the timer with the initial 5 sec delay. 

Un'altra cosa. Nella riga in cui si dispone di questo codice:

progress.setProgress(t); 

Fare attenzione quando si chiama elementi dell'interfaccia utente da altri thread è la fonte di molti mal di testa. Se il tuo gestore si trova in un altro thread, dovresti racchiudere quella chiamata in una funzione e assicurarti che sia chiamata dal thread principale (cioè il thread dell'interfaccia utente). Molti modi per ottenere ciò (non sempre necessario). Uno di loro è in questo modo:

private void updateProgress(int counter) { 
    WhateverActivity.this.runOnUiThread(new Runnable() { 
    public void run() { 
     progress.setProgress(counter); 
    } 
    }); 
} 
6

Fili (e sleep()) sono ingannevoli in Android. Provare a utilizzare un CountDownTimer invece

CountDownTimer counter; 
startTimer(); 
counter.start(); 

private void startTimer() { 

    counter = new CountDownTimer(4000, 500){ 

     @Override 
     public void onFinish() { 

      **DO YOUR STUFF HERE** 
     } 
     @Override 
     public void onTick(long millisUntilFinished) { 
     } 
    }; 
} 

Chiamare la funzione startTimer() dove vuoi e avviare il counter allo stesso tempo.

2

Potresti spiegare che cosa sono e count quando inizia? Posso presumere che siano 0 nel qual caso,

if(count%5==0) //Immediately true. 0 mod 5 == 0. 
    timre--; // 0-- = -1? 
else{ 
    //do nothing 
} 

questo significherebbe che il vostro for loop sta dormendo per -0.01 millisecondi?

for(t=0;t<=100;t++) { 
    sleep((timre)/100); 
    progress.setProgress(t); 
    t += 1; 
} 

Questo spiegherebbe perché è immediatamente eseguire il metodo setProgress. Ma hey, potrei sbagliarmi. Facci sapere quali sono le variabili inizializzate come o in che cosa sono attualmente impostate quando viene colpito il codice!

Grazie,

2

penso che si dovrebbe includere il blocco if all'interno del ciclo for. Come hai scritto il codice, il blocco if viene eseguito solo all'avvio del thread, quindi viene eseguito solo una volta. Pertanto, all'interno del ciclo, la variabile timre non viene mai modificata.

quello che penso che il codice dovrebbe apparire come è:

thread=new Thread(){ 
public void run(){ 
    try{ 

     //*******PROGRESS UPDATE********// 
     for(t=0;t<=100;t++) { 
      if(count%5==0) 
       timre--; 
      sleep((timre)/100); 
      progress.setProgress(t); 
      t += 1; 
     } 
     //****PROGRESS UPDATE OVER****// 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
    finally { 
     finish(); 
    } 
}//run ends 
};//thread ends 
thread.start();//timer starts 
2

Qualcosa del genere dovrebbe funzionare:

thread=new Thread(){ 

++ private float timre; 

++ public void setTimre(float timre) { 
++ this.timre = timre; 
++ } 

public void run(){ 
    try{ 
     if(count%5==0) 
      timre--; 
     else{ 
      //do nothing 
     } 
     //*******PROGRESS UPDATE********// 
     for(t=0;t<=100;t++) { 
      sleep((timre)/100); 
      progress.setProgress(t); 
      t += 1; 
     } 
     //****PROGRESS UPDATE OVER****// 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
    finally { 
     finish(); 
    } 
}//run ends 
};//thread ends 

thread.start(); 

++ if(condition to change the sleeping time) { 
++ try { 
++  thread.interrupt(); 
++  catch(Exception e) { 
++   e.doSomethingCoolWithit(); 
++ } 

++ thread.setTimre(newTimre); 
++ thread.start(); 
++ } 
} 

Anche se questo probabilmente non riuscire quando si cerca di chiamare Thread.start(), per la seconda volta e potrebbe essere necessario creare un nuovo thread.

+0

Come ho già detto, potrebbe essere necessario interrompere il thread corrente e istanziarlo nuovamente –

2

come suggerito @Amaresh, è necessario utilizzare il CountDownTimer per eseguire l'operazione. L'implementazione è viziata in due modi

  • v'è alcuna garanzia che un thread può sempre correre e la tempistica entro il filo potrebbe non essere lo stesso del cosiddetto orologio in tempo reale. È possibile trovare ulteriori informazioni su sleep and time da here.

  • Suppongo che si aggiornerà l'interfaccia utente quando il progresso cambia. In questo caso, CountDownTimer ti risparmia il problema su come rendere la callback al thread principale senza ulteriori gestori.

Se sei interessato, puoi verificare l'implementazione di CountDownTimer dal codice sorgente Android, è semplice e facile da capire.

Nel caso in cui il codice sia in esecuzione su un servizio che richiede tempo, assicurarsi che il timer funzioni effettivamente quando il dispositivo diventa inattivo. In questo caso, potrebbe essere necessario implementare l'allarme sveglia associato a WakefulBroadcastReceiver.