【问题标题】:Delay execution of code in method Java延迟执行 Java 方法中的代码
【发布时间】:2015-01-26 09:33:02
【问题描述】:

我想在我的 java (Android) 程序中每 2 秒后连续生成随机数至少 10 分钟。但我只想暂停/延迟仅以一种方法执行代码,而不是整个程序。

我尝试过像这样使用线程 -

boolean stop = false;
int random_number = 0;

while(true){
    if(stop){  //if stop becomes true, then
        return;  //terminate the method
    }

    random_number = Math.random(); //generate random number
                                   //which is used bu some other
                                   //part of code
    try {
        Thread.sleep(2000);        //delay the code for 2 secs
    } catch(InterruptedException ex) {  //and handle the exceptions
        Thread.currentThread().interrupt();
    }
}

但是,这不起作用,因为Thread.sleep 停止整个程序的执行,而只是停止执行方法内的代码,我的整个屏幕变成空白。

我也尝试过使用Handler,但它也不起作用,因为它不会停止执行我的方法中的代码,而是只是堆叠起来。

这将更好地展示它的工作原理 -

while(true){
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            System.out.println("After 2 secs"); //this gets printed
                                               //later
        }
    }, 2000);
    System.out.println("Before 2 secs"); //this gets printed first
}

所以代码叠加起来就相当于使用 while 循环,而且速度非常慢。

另外,由于我正在为 Android 开发应用程序,我在 Java SE 6 上运行,所以我不能使用 scheduleAtFixedRate。有没有其他方法可以做到这一点?

非常感谢!

【问题讨论】:

  • 为什么不实现定时器,而不是线程?
  • 另外,如果您想使用Thread.sleep(n),请记住在新线程中运行您的方法 - 您所做的可能是在导致 UI 冻结的 UI 线程中运行它。不过,@Stultuske 建议的计时器是个好主意。
  • 好的。让我尝试。非常感谢。
  • @user1685095 正确使用线程并不是基础。他来这里学习。
  • 是的,那是你的恕我直言。我不这么认为。如果您正在编程,您应该了解线程。这是使用线程的基础知识。恕我直言,并发问题可能不是基础。是的,如果他只是在学习,那完全没问题。虽然我建议在完整的计算机而不是移动设备上学习纯 Java,因为那样很容易。

标签: java android delay jdk1.6


【解决方案1】:
private Timer timer;
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                //Generate number
            }
        }, 2000, 2000);

//Documentation (From SDK)
/**
             * Schedule a task for repeated fixed-rate execution after a specific delay
             * has passed.
             *
             * @param task
             *            the task to schedule.
             * @param delay
             *            amount of time in milliseconds before first execution.
             * @param period
             *            amount of time in milliseconds between subsequent    executions.
    public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
                if (delay < 0 || period <= 0) {
                    throw new IllegalArgumentException();
                }
                scheduleImpl(task, delay, period, true);
    }

当你想停止它时

timer.cancel()

【讨论】:

    【解决方案2】:

    选项 1:使用线程,您可以在主 (UI) 线程之外运行您的工作:

    new Thread(new Runnable() {
      // some code here ...
    
      // This might be in a loop.
      try {
        Thread.sleep(2000);
      } catch(InterruptedException ex) {
        // Handle ...
      }
     }
    }).start();
    

    然后,如果您想修改这个新线程(即显示/隐藏按钮、在屏幕上显示某些内容等),请记住将其传递给 UI 线程,因为只有这个线程可以修改 UI。你可以考虑使用Activity.runOnUiThread()

    选项 2: 解决该问题的另一种更 Android 风格的方法是使用 AsyncTask。它包含三个回调,可用于在 UI 线程内外进行工作。此类代码的草图可能如下所示:

     private class MyTask extends AsyncTask<Void, Void, Void> {
       protected Void doInBackground(Void... param) {
         // This method is running off the UI thread.
         // Safe to stop execution here.
    
         return null;
       }
    
       protected void onProgressUpdate(Void... progress) {
         // This methid is running on the UI thread. 
         // Do not stop thread here, but safe to modify the UI.
       }
    
       protected void onPostExecute(Long result) {
         // Also on UI thread, executed once doInBackground()
         // finishes.
       }
     }
    

    选项 3: 然后还有一个Timer,正如@Stultuske 所建议的那样。它不如AsyncTask 灵活,但会为您处理间隔。

    【讨论】:

    • 非常感谢您的回答
    【解决方案3】:

    根据您的需要,您仍然可以使用 Handler 完成您所寻求的。

    您不必在 while 循环中创建/启动处理程序(正如您所注意到的,除非您停止循环本身,否则它只会堆积起来,但这是无稽之谈)。

    只需创建 Handler 并告诉他发布延迟的 Runnable 实例。在最后的 Runnable 中,您检查您的条件。如果仍然可以,则延迟发布另一个 runnable,否则您什么也不做,Handler 将不再执行。

    final Handler handler = new Handler();
    Runnable runnable = new Runnable() {
    
        @Override
        public void run() {
            System.out.println("After 2 secs");
            random_number = Math.random();
    
            if (!stop) // should not be stopped, so we add another runnable;
            {
              handler.postDelayed(this, 2000);
            }
       }
    
    handler.postDelayed(runnable, 2000);
    

    唯一的缺点是,如果设备有一段时间不使用,Handler 可能会冻结,这意味着一旦设备屏幕打开,它将从离开的地方开始倒计时。

    它可以做 1 分钟的正确工作,然后在设备进入睡眠模式时在 1.4 秒阻塞,一旦再次打开,Handler 将完成剩余的 0.6 秒。

    尽管如此,不了解您的需求,您可能不会受到这种行为的影响,并且答案可能适合您。

    【讨论】:

      【解决方案4】:

      如果你想使用线程,这样做:

      Thread t = new Thread(){
          public void run(){
            while(true){
               if(stop) break;
               random_number = Math.random();
               sleep(2000);
            }
          }
      };
      t.start();
      

      【讨论】:

      • stop 是什么。另外,您是否应该停止 while 循环,而不是永远中断。
      • 变量。它具有布尔属性。看问题
      • 啊,是的,错过了。它肯定应该是while(!stop)。其余的都是浪费的线路。您还更改了他的return - 停止线程的愿望,改为break,这只会让它保持空闲循环。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-11
      • 1970-01-01
      • 2013-10-02
      • 2013-03-13
      • 2011-10-18
      • 1970-01-01
      相关资源
      最近更新 更多