->用户单击一个按钮(实际上是一张卡片),然后通过更改此按钮的背景来显示它:
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
}
}
}
如何暂停/休眠线程或进程?
#1 楼
解决此问题的一种方法是使用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);
}
但是,有些人指出上述解决方案会导致内存泄漏,因为它使用了非静态内部和匿名方法。类隐式持有对其外部类活动的引用。当活动上下文被垃圾回收时,这是一个问题。
避免内存泄漏的更复杂的解决方案将
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);
}
请注意,
Runnable
使用对Activity的WeakReference,这在需要访问UI的静态类中是必需的。评论
它有效,但这是在整个代码中引入延迟的一种非常不便的方法,对吗?
– Ehtesh Choudhury
2012年1月20日19:14
我不确定您所说的“不便”是什么意思。处理程序的postDelayed方法旨在告诉Android,您希望在经过一定时间后执行一些代码。
– tronman
2012年2月16日19:45
2年后,这段代码对我有所帮助!谢谢@tronman !! :)
–黎文vin
2012年6月4日上午9:53
您可以简单地将其复制到另一个(最终)变量,例如final Button mynewbutton = mybutton;。并在Handler和Runnable中使用mynewbutton。
– Dzhuneyt
13年5月17日在13:19
@MelvinLai 5年后,此代码对我有所帮助! :)
– Gabrieloliveira
15年11月26日在18:13
#2 楼
您可以尝试这个简短的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处理程序。同样,此解决方案比@tronman更好,因为我们不保留Handler的视图。
此外,在坏线程处创建的Handler也没有问题;)
文档
公共静态无效睡眠(长毫秒)
在API级别1中添加了
返回给定的毫秒数(uptimeMillis)。与sleep(long)类似,但不引发InterruptedException;将interrupt()事件推迟到下一个可中断的操作。
至少经过指定的毫秒数后才返回。
参数
返回之前要进入睡眠状态的毫秒数,以毫秒为单位。
Post代码从View类延迟:
/**
* <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;
}
评论
并让Android UI冻结?不要这样
–shkschneider
13年8月10日在17:24
Ctrl + Shift + O(Eclipse自动导入)
–Dawid Drozd
14年5月17日在9:08
Gelldur,您错过了@RichieHH的评论的意思。与您发布3年之前接受的答案相比,您的建议无助于OP解决他的问题。原因:如OP所示和接受的答案所示的代码都在UI处理程序中运行。当然,说OMG在后台线程中执行此操作无关紧要,除非您演示如何将其放入后台线程中。到那时,您会发现答案比已经接受的答案复杂得多。我是否提到三年前接受了更好的解决方案? :P
–ToolmakerSteve
2014-09-12 17:52
...忘了提起这个建议,使该建议对这个问题格外有用,是因为OP明确希望在延迟后执行UI操作。因此,您将拥有一个解决方案,其中您已经创建了一个后台线程(已经比解决问题所需的权重更大),入睡,然后必须(以某种方式)回到UI线程。 Handler + postRunnable在一个步骤中完成了所有这一切。没有创建第二个线程的系统开销。
–ToolmakerSteve
2014年9月12日18:01
@ToolmakerSteve现在很高兴:D吗?主要问题是:“如何在Android中暂停/休眠线程或进程?”所以我的回答很简单:)。如果有人用谷歌搜索“如何休眠线程”,则会显示此问题。他/她可能正在寻找我的答案:P。但是好吧,我添加了完整的响应;)
–Dawid Drozd
16年5月25日在8:55
#3 楼
我用这个:Thread closeActivity = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
// Do some stuff
} catch (Exception e) {
e.getLocalizedMessage();
}
}
});
评论
e.getLocalizedMessage()应该做什么?
– Philipp Reichart
2012年3月26日在22:28
当我需要简单,通用和快速的异常消息时,我使用e.getLocalizedMessage()
–Byt3
2012-03-30 17:02
但是我敢打赌,在OP询问的情况下,您不会在UI click方法内部执行此操作,这将对UI进行进一步的更新。公认的Handler / postDelayed解决方案具有两个优点:(1)避免了第二线程的系统开销,(1)在UI线程上运行,因此可以进行UI更改而不会引起异常。
–ToolmakerSteve
2014年9月12日18:04
与问题的主要目标没有直接关系,但是您不应该捕获Exception。而是捕获InterruptedException。通过捕获Exception,您将捕获可能出错的所有内容,从而隐藏了原本可以捕获的问题。
–星期四
16-2-3在21:19
#4 楼
您可能不想这样做。通过在按钮单击的事件处理程序中放置一个明确的sleep()
,您实际上将锁定整个UI一秒钟。一种选择是使用某种单次计时器。创建一个TimerTask可以将背景颜色改回默认颜色,并在Timer上安排它。另一种可能性是使用处理程序。有一个关于某人的教程,该人从使用计时器切换为使用处理程序。
顺便说一句,您不能暂停一个进程。 Java(或Android)进程至少具有1个线程,并且您只能休眠线程。
#5 楼
我使用CountDownTimenew CountDownTimer(5000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
// do something after 1s
}
@Override
public void onFinish() {
// do something end times 5s
}
}.start();
评论
这很有用。
– UzaySan
19年2月4日在18:37
#6 楼
这是我一天结束时所做的-现在可以正常使用:@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);
}
评论
为什么不发布延迟?无需计时器。
– RichieHH
2014年7月29日在7:40
#7 楼
除了Yankowsky先生的答案外,您还可以使用postDelayed()
。这在任何View
(例如您的卡)上都可用,并且需要Runnable
和延迟时间。在该延迟后执行Runnable
。#8 楼
这是我的示例创建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();
}
}
评论
在问题已经解决好多年后又增加了一个答案,与这个问题无关,因为它没有满足人们对能够执行UI工作的要求。您无法在此处执行UI工作,因为您正在新线程上运行。不在UI线程上。
–ToolmakerSteve
2014年9月12日18:08
在UX方面,向用户显示阻止对话框以加载数据不是很好。
– 2Dee
15年3月16日在8:39
如果我们不需要更改ui,我想这种方法比在主线程上运行Handlers更好。但是,Timer类或在其他线程上显式运行Handler呢?
– JCarlosR
12月18日19:19
#9 楼
或者您可以使用:android.os.SystemClock.sleep(checkEvery)
,它的优点是不需要包装
try ... catch
。#10 楼
如果您使用Kotlin和协程,只需执行GlobalScope.launch {
delay(3000) // In ms
//Code after sleep
}
,如果您需要更新UI
GlobalScope.launch {
delay(3000)
GlobalScope.launch(Dispatchers.Main) {
//Action on UI thread
}
}
#11 楼
我知道这是一个旧线程,但是在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
希望这对某人有帮助...
#12 楼
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答案中所述的“静态类”方法结合使用,
评论
哦,只需使用经典的线程暂停块:while(true){}@ KristoferA-Huagati.com我不确定您是在讽刺还是真的有一些Dalvik / Android魔术,因此在Android上可以接受。你能澄清一下吗?很抱歉怀疑,但我问,因为通常不鼓励while(!conditionCheck()){}。
“但是,这不起作用。” “我也尝试过(但不起作用)”。这是一个典型的例子,说明有问题而不给出症状。这些尝试以什么方式无法满足您的要求?线程没有暂停吗?您收到错误消息了吗?