2015-06-14 46 views
6

Co próbowałem zrobić, to zmniejszyć opóźnienie timera za każdym razem, gdy licznik staje się wielokrotnością 5. Ale, jak tylko kod wszedł do bloku if, zatrzymał inkrementację timera. Nie mogę zrozumieć, co się dzieje.Jak zmienić opóźnienie wątku snu/timera w Androidzie podczas uruchamiania?

Jest to kod

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

Czy możesz pokazać więcej kodu? Gdzie zainicjujesz timer? – Wishmaster

Odpowiedz

5

Thread.sleep() nie jest gwarantowane. Oznacza to, że może on spać lub może nie spać przez określony czas z różnych powodów, które są poza tematem dla tego pytania.

Jeśli szukać w sieci dla „zegar w android” prawdopodobnie będzie lądować na te dwa: https://developer.android.com/reference/java/util/Timer.html i https://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor.html

Można je sprawdzić, jednak nie będę korzystać z tych, ponieważ dostarczają one wiele innych funkcjonalności jak sugeruje nazwa ("ScheduledThreadPoolExecutor"). Nie potrzebujesz tego, ponieważ jest to najprawdopodobniej używane w dużych systemach z wieloma wątkami itp.

Jeśli dobrze rozumiem Twój kod, próbujesz zaktualizować pasek postępu. Do tego, co próbujesz zrobić, sugerowałbym użycie handler'a.Jednym z głównych zastosowań handlera jest zaplanować wiadomości i runnables być wykonany jako pewnym momencie w przyszłości, jak określono w docs tutaj: http://developer.android.com/reference/android/os/Handler.html

zrobiłbym to tak:

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. 

Jeszcze jedna rzecz. W wierszu, w którym masz ten kod:

progress.setProgress(t); 

Bądź ostrożny podczas wywoływania elementów interfejsu z innych wątków jest źródłem wielu głowy. Jeśli twój program obsługi znajduje się w innym wątku, powinieneś zawinąć to wywołanie w funkcję i upewnić się, że jest wywoływane z głównego wątku (tj. Wątku UI). Wiele sposobów na osiągnięcie tego (nie zawsze jest konieczne). Jednym z nich jest tak:

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

Nici (i sleep()) są trudne w android. Spróbuj użyć CountDownTimer zamiast

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

wywołać funkcję startTimer() gdzie chcesz i rozpocząć counter w tym samym czasie.

2

Czy możesz wyjaśnić, co to jest timre i , kiedy to się zaczyna? Mogę przypuszczać, że są 0 W takim przypadku,

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

Oznaczałoby to, że for loop śpi na -0.01 milisekund?

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

To wyjaśniałoby, dlaczego to natychmiast uruchomiony metodę setProgress. Ale hej, mógłbym się mylić. Poinformuj nas, jakie zmienne zostały zainicjowane lub, do czego są one aktualnie ustawione, gdy kod zostanie trafiony!

Dzięki,

2

myślę, że należy obejmować jeśli blok wewnątrz pętli for. Jak już napisałeś kod, blok if jest wykonywany tylko wtedy, gdy zaczyna się wątek, więc jest wykonywany tylko raz. Dlatego wewnątrz pętli zmienna czasowa nigdy nie jest zmieniana.

Co myślę, że Twój kod powinien wyglądać tak jest:

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

Coś jak to powinno działać:

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

Choć będzie to prawdopodobnie zawieść podczas próby wywołania thread.start() po raz drugi i być może trzeba będzie utworzyć nowy wątek.

+0

Tak jak powiedziałem, może być konieczne zatrzymanie bieżącego wątku i utworzenie instancji ponownie –

2

jak sugeruje @Amaresh, należy użyć CountDownTimer aby wykonać zadanie. Implementacja jest wadliwy dwojako

  • nie ma gwarancji, że wątek można zawsze uruchomić i czas w wątku nie może być taka sama jak tzw zegar czasu rzeczywistego. Możesz znaleźć więcej informacji na temat snu i czasu od here.

  • Zakładam, że zamierzasz zaktualizować interfejs użytkownika, gdy postęp się zmieni. W takim przypadku CountDownTimer oszczędza kłopotów z nawiązywaniem połączenia z głównym wątkiem bez dodatkowych funkcji obsługi.

Jeśli jesteś zainteresowany, możesz sprawdzić implementację CountDownTimer z kodu źródłowego Androida, jest to proste i łatwe do zrozumienia.

Jeśli Twój kod działa na czasochłonnej usłudze, upewnij się, że czasomierz działa, gdy urządzenie przestanie działać. W takim przypadku może być konieczne zaimplementowanie budzika alarmowego w połączeniu z WakefulBroadcastReceiver.