如何在Android中暂停/睡眠线程或进程?

发布于 2024-08-07 05:07:21 字数 1041 浏览 2 评论 0 原文

我想在两行代码之间暂停一下,让我解释一下:

->用户单击一个按钮(实际上是一张卡片),我通过更改该按钮的背景来显示它:

thisbutton.setBackgroundResource(R.drawable.icon);

->假设 1 秒后,我需要通过更改背景来返回到按钮之前的状态:

thisbutton.setBackgroundResource(R.drawable.defaultcard);

->我尝试使用以下命令暂停这两行代码之间的线程:

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

但是,这不起作用。也许我需要暂停的是进程而不是线程?

我也尝试过(但它不起作用):

new Reminder(5);

这样:

public class Reminder {

Timer timer;

        public Reminder(int seconds) {
            timer = new Timer();
            timer.schedule(new RemindTask(), seconds*1000);
        }

        class RemindTask extends TimerTask {
            public void run() {
                System.out.format("Time's up!%n");
                timer.cancel(); //Terminate the timer thread
            }
        }  
    }

如何暂停/睡眠线程或进程?

I want to make a pause between two lines of code, Let me explain a bit:

-> the user clicks a button (a card in fact) and I show it by changing the background of this button:

thisbutton.setBackgroundResource(R.drawable.icon);

-> after let's say 1 second, I need to go back to the previous state of the button by changing back its background:

thisbutton.setBackgroundResource(R.drawable.defaultcard);

-> I've tried to pause the thread between these two lines of code with:

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

However, this does not work. Maybe it's the process and not the Thread that I need to pause?

I've also tried (but it doesn't work):

new Reminder(5);

With this:

public class Reminder {

Timer timer;

        public Reminder(int seconds) {
            timer = new Timer();
            timer.schedule(new RemindTask(), seconds*1000);
        }

        class RemindTask extends TimerTask {
            public void run() {
                System.out.format("Time's up!%n");
                timer.cancel(); //Terminate the timer thread
            }
        }  
    }

How can I pause/sleep the thread or process?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

眼眸 2024-08-14 05:07:21

解决此问题的一种方法是使用 Handler.postDelayed() 方法。一些 Google培训材料建议了相同的解决方案。

@Override
public void onClick(View v) {
    my_button.setBackgroundResource(R.drawable.icon);

    Handler handler = new Handler(); 
    handler.postDelayed(new Runnable() {
         @Override 
         public void run() { 
              my_button.setBackgroundResource(R.drawable.defaultcard); 
         } 
    }, 2000); 
}

然而,有些人指出,上述解决方案 会导致内存泄漏泄漏,因为它使用非静态内部匿名类,该类隐式保存对其外部类(即活动)的引用。当活动上下文被垃圾收集时,这是一个问题。

避免内存泄漏的更复杂的解决方案是使用活动内的静态内部类对 HandlerRunnable 进行子类化,因为静态内部类不持有对其外部类的隐式引用:

private static class MyHandler extends Handler {}
private final MyHandler mHandler = new MyHandler();

public static class MyRunnable implements Runnable {
    private final WeakReference<Activity> mActivity;

    public MyRunnable(Activity activity) {
        mActivity = new WeakReference<>(activity);
    }

    @Override
    public void run() {
        Activity activity = mActivity.get();
        if (activity != null) {
            Button btn = (Button) activity.findViewById(R.id.button);
            btn.setBackgroundResource(R.drawable.defaultcard);
        }
    }
}

private MyRunnable mRunnable = new MyRunnable(this);

public void onClick(View view) {
    my_button.setBackgroundResource(R.drawable.icon);

    // Execute the Runnable in 2 seconds
    mHandler.postDelayed(mRunnable, 2000);
}

请注意,Runnable 使用 WeakReference 到 Activity,这在需要访问 UI 的静态类中是必需的。

One solution to this problem is to use the Handler.postDelayed() method. Some Google training materials suggest the same solution.

@Override
public void onClick(View v) {
    my_button.setBackgroundResource(R.drawable.icon);

    Handler handler = new Handler(); 
    handler.postDelayed(new Runnable() {
         @Override 
         public void run() { 
              my_button.setBackgroundResource(R.drawable.defaultcard); 
         } 
    }, 2000); 
}

However, some have pointed out that the solution above causes a memory leak because it uses a non-static inner and anonymous class which implicitly holds a reference to its outer class, the activity. This is a problem when the activity context is garbage collected.

A more complex solution that avoids the memory leak subclasses the Handler and Runnable with static inner classes inside the activity since static inner classes do not hold an implicit reference to their outer class:

private static class MyHandler extends Handler {}
private final MyHandler mHandler = new MyHandler();

public static class MyRunnable implements Runnable {
    private final WeakReference<Activity> mActivity;

    public MyRunnable(Activity activity) {
        mActivity = new WeakReference<>(activity);
    }

    @Override
    public void run() {
        Activity activity = mActivity.get();
        if (activity != null) {
            Button btn = (Button) activity.findViewById(R.id.button);
            btn.setBackgroundResource(R.drawable.defaultcard);
        }
    }
}

private MyRunnable mRunnable = new MyRunnable(this);

public void onClick(View view) {
    my_button.setBackgroundResource(R.drawable.icon);

    // Execute the Runnable in 2 seconds
    mHandler.postDelayed(mRunnable, 2000);
}

Note that the Runnable uses a WeakReference to the Activity, which is necessary in a static class that needs access to the UI.

轮廓§ 2024-08-14 05:07:21

您可以尝试这个,它简短

SystemClock.sleep(7000);

警告:永远不要在 UI 线程上执行此操作。

用它来睡觉,例如。后台线程。


您的问题的完整解决方案将是:
这是可用的 API 1,

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View button) {
                button.setBackgroundResource(R.drawable.avatar_dead);
                final long changeTime = 1000L;
                button.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        button.setBackgroundResource(R.drawable.avatar_small);
                    }
                }, changeTime);
            }
        });

无需创建 tmp Handler。此外,这个解决方案比 @tronman 更好,因为我们不通过 Handler 保留视图。
此外,我们在错误线程中创建的处理程序也没有问题;)

文档

公共静态无效睡眠(长毫秒)

在 API 级别 1 中添加

返回之前等待给定的毫秒数(uptimeMillis)。与sleep(long)类似,但不抛出InterruptedException;中断()事件被推迟到
下一个可中断操作。
在至少经过指定的毫秒数之前不返回

参数

ms 返回之前的睡眠时间,以毫秒为单位的正常运行时间。

ms,以毫秒为单位的正常运行时间。 View 类中的 postDelayed 代码:

/**
 * <p>Causes the Runnable to be added to the message queue, to be run
 * after the specified amount of time elapses.
 * The runnable will be run on the user interface thread.</p>
 *
 * @param action The Runnable that will be executed.
 * @param delayMillis The delay (in milliseconds) until the Runnable
 *        will be executed.
 *
 * @return true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the Runnable will be processed --
 *         if the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 *
 * @see #post
 * @see #removeCallbacks
 */
public boolean postDelayed(Runnable action, long delayMillis) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.postDelayed(action, delayMillis);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
    return true;
}

You can try this one it is short

SystemClock.sleep(7000);

WARNING: Never, ever, do this on a UI thread.

Use this to sleep eg. background thread.


Full solution for your problem will be:
This is available API 1

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View button) {
                button.setBackgroundResource(R.drawable.avatar_dead);
                final long changeTime = 1000L;
                button.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        button.setBackgroundResource(R.drawable.avatar_small);
                    }
                }, changeTime);
            }
        });

Without creating tmp Handler. Also this solution is better than @tronman because we do not retain view by Handler.
Also we don't have problem with Handler created at bad thread ;)

Documentation

public static void sleep (long ms)

Added in API level 1

Waits a given number of milliseconds (of uptimeMillis) before returning. Similar to sleep(long), but does not throw InterruptedException; interrupt() events are deferred until the
next interruptible operation.
Does not return until at least the specified number of milliseconds has elapsed.

Parameters

ms to sleep before returning, in milliseconds of uptime.

Code for postDelayed from View class:

/**
 * <p>Causes the Runnable to be added to the message queue, to be run
 * after the specified amount of time elapses.
 * The runnable will be run on the user interface thread.</p>
 *
 * @param action The Runnable that will be executed.
 * @param delayMillis The delay (in milliseconds) until the Runnable
 *        will be executed.
 *
 * @return true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the Runnable will be processed --
 *         if the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 *
 * @see #post
 * @see #removeCallbacks
 */
public boolean postDelayed(Runnable action, long delayMillis) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.postDelayed(action, delayMillis);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
    return true;
}
可是我不能没有你 2024-08-14 05:07:21

我用这个:

Thread closeActivity = new Thread(new Runnable() {
  @Override
  public void run() {
    try {
      Thread.sleep(3000);
      // Do some stuff
    } catch (Exception e) {
      e.getLocalizedMessage();
    }
  }
});

I use this:

Thread closeActivity = new Thread(new Runnable() {
  @Override
  public void run() {
    try {
      Thread.sleep(3000);
      // Do some stuff
    } catch (Exception e) {
      e.getLocalizedMessage();
    }
  }
});
木槿暧夏七纪年 2024-08-14 05:07:21

我使用倒计时

new CountDownTimer(5000, 1000) {

    @Override
    public void onTick(long millisUntilFinished) {
        // do something after 1s
    }

    @Override
    public void onFinish() {
        // do something end times 5s
    }

}.start(); 

I use CountDownTime

new CountDownTimer(5000, 1000) {

    @Override
    public void onTick(long millisUntilFinished) {
        // do something after 1s
    }

    @Override
    public void onFinish() {
        // do something end times 5s
    }

}.start(); 
随风而去 2024-08-14 05:07:21

您可能不想那样做。通过在按钮单击事件处理程序中放置显式 sleep() ,您实际上会锁定整个 UI 一秒钟。一种替代方法是使用某种单次计时器。创建一个 TimerTask 将背景颜色更改回默认颜色,然后在计时器上安排它。

另一种可能性是使用 Handler。有教程,介绍了不再使用计时器的人使用处理程序。

顺便说一句,您无法暂停进程。一个Java(或Android)进程至少有1个线程,并且只能休眠线程。

You probably don't want to do it that way. By putting an explicit sleep() in your button-clicked event handler, you would actually lock up the whole UI for a second. One alternative is to use some sort of single-shot Timer. Create a TimerTask to change the background color back to the default color, and schedule it on the Timer.

Another possibility is to use a Handler. There's a tutorial about somebody who switched from using a Timer to using a Handler.

Incidentally, you can't pause a process. A Java (or Android) process has at least 1 thread, and you can only sleep threads.

清醇 2024-08-14 05:07:21

这就是我在一天结束时所做的 - 现在工作正常:

@Override
    public void onClick(View v) {
        my_button.setBackgroundResource(R.drawable.icon);
        // SLEEP 2 SECONDS HERE ...
        final Handler handler = new Handler(); 
        Timer t = new Timer(); 
        t.schedule(new TimerTask() { 
                public void run() { 
                        handler.post(new Runnable() { 
                                public void run() { 
                                 my_button.setBackgroundResource(R.drawable.defaultcard); 
                                } 
                        }); 
                } 
        }, 2000); 
    }

This is what I did at the end of the day - works fine now :

@Override
    public void onClick(View v) {
        my_button.setBackgroundResource(R.drawable.icon);
        // SLEEP 2 SECONDS HERE ...
        final Handler handler = new Handler(); 
        Timer t = new Timer(); 
        t.schedule(new TimerTask() { 
                public void run() { 
                        handler.post(new Runnable() { 
                                public void run() { 
                                 my_button.setBackgroundResource(R.drawable.defaultcard); 
                                } 
                        }); 
                } 
        }, 2000); 
    }
半仙 2024-08-14 05:07:21

除了 Yankowsky 先生的答案之外,您还可以使用 postDelayed()。这在任何View(例如您的卡)上都可用,并且需要一个Runnable和一个延迟时间。它会在延迟后执行 Runnable。

In addition to Mr. Yankowsky's answers, you could also use postDelayed(). This is available on any View (e.g., your card) and takes a Runnable and a delay period. It executes the Runnable after that delay.

裂开嘴轻声笑有多痛 2024-08-14 05:07:21

这是我的示例

创建一个 Java Utils

    import android.app.ProgressDialog;
    import android.content.Context;
    import android.content.Intent;

    public class Utils {

        public static void showDummyWaitingDialog(final Context context, final Intent startingIntent) {
            // ...
            final ProgressDialog progressDialog = ProgressDialog.show(context, "Please wait...", "Loading data ...", true);

            new Thread() {
                public void run() {
                    try{
                        // Do some work here
                        sleep(5000);
                    } catch (Exception e) {
                    }
                    // start next intent
                    new Thread() {
                        public void run() {
                        // Dismiss the Dialog 
                        progressDialog.dismiss();
                        // start selected activity
                        if ( startingIntent != null) context.startActivity(startingIntent);
                        }
                    }.start();
                }
            }.start();  

        }

    }    

This is my example

Create a Java Utils

    import android.app.ProgressDialog;
    import android.content.Context;
    import android.content.Intent;

    public class Utils {

        public static void showDummyWaitingDialog(final Context context, final Intent startingIntent) {
            // ...
            final ProgressDialog progressDialog = ProgressDialog.show(context, "Please wait...", "Loading data ...", true);

            new Thread() {
                public void run() {
                    try{
                        // Do some work here
                        sleep(5000);
                    } catch (Exception e) {
                    }
                    // start next intent
                    new Thread() {
                        public void run() {
                        // Dismiss the Dialog 
                        progressDialog.dismiss();
                        // start selected activity
                        if ( startingIntent != null) context.startActivity(startingIntent);
                        }
                    }.start();
                }
            }.start();  

        }

    }    
丶情人眼里出诗心の 2024-08-14 05:07:21

或者您可以使用:

android.os.SystemClock.sleep(checkEvery)

其优点是不需要包装 try ... catch

Or you could use:

android.os.SystemClock.sleep(checkEvery)

which has the advantage of not requiring a wrapping try ... catch.

随心而道 2024-08-14 05:07:21

如果您使用 Kotlin 和 协程,您可以简单地执行

GlobalScope.launch {
   delay(3000) // In ms
   //Code after sleep
}

以下操作如果您需要更新 UI

GlobalScope.launch {
  delay(3000)
  GlobalScope.launch(Dispatchers.Main) {
    //Action on UI thread
  }
}

If you use Kotlin and coroutines, you can simply do

GlobalScope.launch {
   delay(3000) // In ms
   //Code after sleep
}

And if you need to update UI

GlobalScope.launch {
  delay(3000)
  GlobalScope.launch(Dispatchers.Main) {
    //Action on UI thread
  }
}
眼眸里的快感 2024-08-14 05:07:21

我知道这是一个旧线程,但在 Android 文档中我找到了一个非常适合我的解决方案...

new CountDownTimer(30000, 1000) {

    public void onTick(long millisUntilFinished) {
        mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
    }

    public void onFinish() {
        mTextField.setText("done!");
    }
}.start();

https://developer.android.com/reference/android/os/CountDownTimer.html

希望这对某人有帮助......

I know this is an old thread, but in the Android documentation I found a solution that worked very well for me...

new CountDownTimer(30000, 1000) {

    public void onTick(long millisUntilFinished) {
        mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
    }

    public void onFinish() {
        mTextField.setText("done!");
    }
}.start();

https://developer.android.com/reference/android/os/CountDownTimer.html

Hope this helps someone...

轮廓§ 2024-08-14 05:07:21
  class MyActivity{
    private final Handler handler = new Handler();
    private Runnable yourRunnable;
    protected void onCreate(@Nullable Bundle savedInstanceState) {
       // ....
       this.yourRunnable = new Runnable() {
               @Override
               public void run() {
                   //code
               }
            };

        this.handler.postDelayed(this.yourRunnable, 2000);
       }


     @Override
  protected void onDestroy() {
      // to avoid memory leaks
      this.handler.removeCallbacks(this.yourRunnable);
      }
    }

并确保您可以将其与“静态类”方法结合起来,如 tronman 答案中所述

  class MyActivity{
    private final Handler handler = new Handler();
    private Runnable yourRunnable;
    protected void onCreate(@Nullable Bundle savedInstanceState) {
       // ....
       this.yourRunnable = new Runnable() {
               @Override
               public void run() {
                   //code
               }
            };

        this.handler.postDelayed(this.yourRunnable, 2000);
       }


     @Override
  protected void onDestroy() {
      // to avoid memory leaks
      this.handler.removeCallbacks(this.yourRunnable);
      }
    }

And to be double sure you can be combined it with the "static class" method as described in the tronman answer

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文