如何在 Android 中暂停/睡眠线程或进程?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1520887/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to pause / sleep thread or process in Android?
提问by Hubert
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:
-> 假设 1 秒后,我需要通过更改背景来返回按钮的先前状态:
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?
如何暂停/休眠线程或进程?
回答by tronman
One solution to this problem is to use the Handler.postDelayed()method. Some Google training materialssuggest the same solution.
此问题的一种解决方案是使用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);
}
However, some have pointed out that the solution above causes a memory leakbecause 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:
避免内存泄漏的更复杂的解决方案在活动中使用静态内部类对Handler
和Runnable
进行子类化,因为静态内部类不包含对其外部类的隐式引用:
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 WeakReferenceto the Activity, which is necessary in a static class that needs access to the UI.
请注意,ActivityRunnable
使用WeakReference,这在需要访问 UI 的静态类中是必需的。
回答by Dawid Drozd
You can try this one it is short
你可以试试这个它很短
SystemClock.sleep(7000);
WARNING: Never, ever, do this on a UI thread.
警告:永远不要在 UI 线程上执行此操作。
Use this to sleep eg. background thread.
用它来睡觉,例如。后台线程。
Full solution for your problem will be: This is available API 1
您的问题的完整解决方案将是:这是可用的 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 ;)
无需创建 tmp 处理程序。此外,此解决方案比 @tronman 更好,因为我们不保留 Handler 的视图。我们也没有在坏线程上创建 Handler 的问题;)
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 returnuntil at least the specified number of milliseconds has elapsed.
Parameters
msto sleep before returning, in milliseconds of uptime.
公共静态无效睡眠(长毫秒)
在 API 级别 1 中添加
在返回之前等待给定的毫秒数(uptimeMillis)。类似于 sleep(long),但不抛出 InterruptedException;中断()事件被推迟到下一个可中断的操作。难道不返回,直到至少指定的毫秒数已过。
参数
MS睡眠返回,在正常运行时间的毫秒之前。
Code for postDelayedfrom View class:
来自 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;
}
回答by Byt3
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();
}
}
});
回答by Daniel Yankowsky
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 TimerTaskto change the background color back to the default color, and schedule it on the Timer.
你可能不想那样做。通过sleep()
在您的按钮单击事件处理程序中放置一个显式,您实际上会将整个 UI 锁定一秒钟。一种替代方法是使用某种单发Timer。创建一个TimerTask将背景颜色更改回默认颜色,并将其安排在 Timer 上。
Another possibility is to use a Handler. There's a tutorialabout somebody who switched from using a Timer to using a Handler.
另一种可能性是使用Handler。有一个关于某人从使用计时器切换到使用处理程序的教程。
Incidentally, you can't pause a process. A Java (or Android) process has at least 1 thread, and you can only sleep threads.
顺便说一下,您不能暂停进程。一个 Java(或 Android)进程至少有 1 个线程,并且您只能休眠线程。
回答by vudandroid
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();
回答by Hubert
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);
}
回答by CommonsWare
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.
除了 Yankowsky 先生的回答,您还可以使用postDelayed()
. 这在任何View
(例如,您的卡)上都可用,并且需要一个Runnable
和一个延迟期。它Runnable
在延迟之后执行。
回答by Stefano
This is my example
这是我的例子
Create a Java Utils
创建 Java 实用程序
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();
}
}
回答by aaaa
Or you could use:
或者你可以使用:
android.os.SystemClock.sleep(checkEvery)
which has the advantage of not requiring a wrapping try ... catch
.
其优点是不需要包装try ... catch
。
回答by Guillaume
If you use Kotlin and coroutines, you can simply do
如果你使用 Kotlin 和coroutines,你可以简单地做
GlobalScope.launch {
delay(3000) // In ms
//Code after sleep
}
And if you need to update UI
如果你需要更新 UI
GlobalScope.launch {
delay(3000)
GlobalScope.launch(Dispatchers.Main) {
//Action on UI thread
}
}