Как изменить задержку потока сна / таймера в android во время выполнения?

То, что я пытался сделать, это уменьшить задержку таймера каждый раз, когда счетчик становится кратным 5. Но, как только код вводит блок if, он перестает увеличивать таймер. Я не понимаю, что происходит.

Это код

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 

Темы (и sleep() ) сложны в android. Попробуйте вместо этого использовать CountDownTimer

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

Вызовите функцию startTimer() где хотите, и запустите counter одновременно.

Thread.sleep () не гарантируется. Это означает, что он может или не может спать в течение длительного времени по разным причинам, которые не соответствуют теме этого вопроса.

Если вы ищете сеть для «таймера в андроиде», вы, вероятно, приземлитесь на эти два: https://developer.android.com/reference/java/util/Timer.html и https://developer.android.com/reference /java/util/concurrent/ScheduledThreadPoolExecutor.html

Вы можете проверить их, однако я бы не использовал их, поскольку они предоставляют множество других функций, как следует из названия («ScheduledThreadPoolExecutor»). Вам это не нужно, так как это, скорее всего, будет использоваться для больших систем с большим количеством потоков и т. Д. …

Если я правильно понимаю ваш код, вы пытаетесь обновить индикатор выполнения. Для того, что вы пытаетесь сделать, я бы предложил использовать обработчик. Одним из основных применений обработчика является планирование сообщений и runnables, которые будут выполняться как некоторые точки в будущем, как указано в документах здесь: http://developer.android.com/reference/android/os/Handler.html

Я бы сделал это так:

  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. 

Еще кое-что. В строке, где у вас есть этот код:

 progress.setProgress(t); 

Будьте осторожны при вызове элементов пользовательского интерфейса из других потоков, это источник большого количества головной боли. Если ваш обработчик находится в другом потоке, вы должны перенести этот вызов в функцию и убедиться, что он вызывается из основного потока (т.е. потока пользовательского интерфейса). Много способов достичь этого (не всегда необходимо). Один из них выглядит следующим образом:

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

Не могли бы вы объяснить, что такое timre и count , когда это начинается? Я могу предположить, что они 0 в этом случае,

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

Это будет означать, что ваш for loop for- -0.01 составляет -0.01 миллисекунды?

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

Это объясняет, почему он немедленно запускает метод setProgress . Но эй, я мог ошибаться. Сообщите нам, что эти переменные инициализируются как или что они в настоящее время установлены, когда код попал!

Благодаря,

Я думаю, что вы должны включить блок if внутри цикла for. Когда вы написали код, блок if выполняется только при запуске потока, поэтому он выполняется только один раз. Поэтому внутри цикла переменная timre никогда не изменяется.

Я думаю, что ваш код должен выглядеть так:

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

Что-то вроде этого должно работать:

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

Хотя это, вероятно, не удастся при попытке вызвать thread.start () во второй раз, и вам может понадобиться создать новый поток.

Как предложил @Amaresh, вы должны использовать CountDownTimer для выполнения задачи. Ваша реализация ошибочна двумя способами

  • Нет никакой гарантии, что поток всегда может выполняться, а время в потоке может быть не таким, как так называемое время реального времени. Здесь вы можете найти больше информации о сне и времени.

  • Я предполагаю, что вы собираетесь обновлять пользовательский интерфейс, когда прогресс изменится. В этом случае CountDownTimer избавляет вас от проблем с тем, как сделать обратный вызов в основной поток без дополнительных обработчиков.

Если вам интересно, вы можете проверить реализацию CountDownTimer из исходного кода Android, это прямолинейно и легко понять.

В случае, если ваш код работает на ресурсоемкой службе, убедитесь, что ваш таймер работает, когда устройство переходит в режим ожидания. В этом случае вам может потребоваться внедрение бодрствования в сочетании с WakefulBroadcastReceiver .