如何在运行时更改 android 中 sleep/timer 线程的延迟?

How to change the delay of sleep/timer thread in android during runtime?

我试图做的是在每次计数器变成 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

你能解释一下 timrecount 是什么时候开始的吗?我可以假设它们是 0 在这种情况下,

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

这意味着您的 for loop 正在休眠 -0.01 毫秒?

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

这可以解释为什么它立即 运行 setProgress 方法。 但是,嘿,我可能是错的。让我们知道这些变量被初始化为什么,或者当代码被命中时它们当前被设置为什么!

谢谢,

我认为您应该在 for 循环中包含 if 块。正如您编写的代码,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(){

++    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() 时可能会失败,您可能需要创建一个新线程。

Thread.sleep() 无法保证。这意味着由于各种原因,它可能会或可能不会休眠您想要的持续时间,这些原因超出了这个问题的主题。

如果您在网上搜索 "timer in android",您可能会找到这两个:https://developer.android.com/reference/java/util/Timer.html and https://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor.html

您可以查看它们,但是,我不会使用它们,因为它们提供了许多其他功能,正如其名称所示 ("ScheduledThreadPoolExecutor")。您不需要它,因为它最有可能用于具有大量线程等的大型系统...

如果我正确理解了您的代码,那么您正在尝试更新进度条。 对于您要尝试做的事情,我建议使用处理程序。处理程序的主要用途之一是安排消息和可运行对象在未来某个时间点执行,如此处文档中所指定: 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);

从其他线程调用 UI 元素时要小心,这是很多麻烦的根源。如果您的处理程序在另一个线程中,您应该将该调用包装在一个函数中,并确保它是从主线程(即 UI 线程)调用的。实现这一目标的方法有很多(您并不总是必需的)。其中一个是这样的:

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

正如@Amaresh 建议的那样,您应该使用 CountDownTimer 来执行任务。您的实施在两个方面存在缺陷

  • 不能保证一个线程总能运行并且线程内的时间不一定和所谓的真实时钟时间一样。您可以从 here.

  • 中找到有关睡眠和时间的更多信息
  • 我假设您要在进度变化时更新 UI。在这种情况下,CountDownTimer 为您省去了如何在没有额外处理程序的情况下回调到主线程的麻烦。

有兴趣的可以查看Android源码中CountDownTimer的实现,简单易懂。

如果您的代码 运行 正在执行一项耗时的服务,请确保您的计时器在设备空闲时正常工作。在这种情况下,您可能需要实现与 WakefulBroadcastReceiver 配对的唤醒警报。