如何在运行时更改android中睡眠/计时器线程的延迟?

时间:2015-06-14 11:06:40

标签: java android timer runtime sleep

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

6 个答案:

答案 0 :(得分:6)

线程(和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

答案 1 :(得分:5)

不保证Thread.sleep()。这意味着,由于各种原因,您可能会或可能不会在您想要的时间内睡觉。

如果你在网上搜索&#34;计时器在android&#34;你可能会落在这两个上:https://developer.android.com/reference/java/util/Timer.htmlhttps://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor.html

你可以检查它们,但是,我不会使用它们,因为它们提供了许多其他功能,如名称所示(&#34; ScheduledThreadPoolExecutor&#34;)。你不需要这个,因为这很可能用于拥有大量线程等的大型系统......

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

答案 2 :(得分:2)

您可以解释一下这个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方法。 但是,嘿,我可能是错的。让我们知道在代码被命中时,这些变量被初始化为什么或者它们当前被设置为什么!

谢谢,

答案 3 :(得分:2)

我认为你应该在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

答案 4 :(得分:2)

这样的事情应该有效:

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

答案 5 :(得分:2)

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

  • 无法保证线程始终可以运行,并且线程内的时序可能与所谓的实际时钟时间不同。您可以从here找到有关睡眠和时间的更多信息。

  • 我假设您将在进度发生变化时更新UI。在这种情况下,CountDownTimer可以省去如何在没有额外处理程序的情况下回调主线程的麻烦。

如果您有兴趣,可以从Android源代码检查CountDownTimer的实现,它是直截了当且易于理解的。

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