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

How to pause / sleep thread or process in Android?

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

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

1
thisbutton.setBackgroundResource(R.drawable.icon);

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

1
thisbutton.setBackgroundResource(R.drawable.defaultcard);

->我尝试在这两行代码之间暂停线程:

1
2
3
4
5
6
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

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

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

1
new Reminder(5);

用这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
            }
        }  
    }

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


这个问题的一个解决方案是使用handler.postDelayed()方法。一些谷歌培训材料也提出了同样的解决方案。

1
2
3
4
5
6
7
8
9
10
11
12
@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);
}

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

避免内存泄漏的更复杂的解决方案将HandlerRunnable子类与活动中的静态内部类相关联,因为静态内部类不包含对其外部类的隐式引用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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,这在需要访问UI的静态类中是必需的。


你可以试试这个它很短

1
SystemClock.sleep(7000);

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

使用这个来休眠,例如后台线程。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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更好,因为我们不按处理程序保留视图。我们也不存在汉德勒在坏线程创建的问题;

文档

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.

从视图类延迟后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
 * <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;
}


我用这个:

1
2
3
4
5
6
7
8
9
10
11
Thread closeActivity = new Thread(new Runnable() {
  @Override
  public void run() {
    try {
      Thread.sleep(3000);
      // Do some stuff
    } catch (Exception e) {
      e.getLocalizedMessage();
    }
  }
});


你可能不想那样做。通过在单击按钮的事件处理程序中放置一个显式的sleep(),您实际上可以将整个UI锁定一秒钟。另一种选择是使用某种单发计时器。创建一个timertask,将背景色更改回默认颜色,并在计时器上安排它。

另一种可能是使用处理程序。有一个关于某人从使用计时器转向使用处理程序的教程。

顺便说一下,你不能暂停一个进程。Java(或Android)进程至少有1个线程,并且只能睡眠线程。


我使用倒计时

1
2
3
4
5
6
7
8
9
10
11
12
13
new CountDownTimer(5000, 1000) {

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

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

}.start();


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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);
    }


除了Yankowsky先生的回答之外,您还可以使用postDelayed()。这在任何View上都可用(例如,您的卡),需要Runnable和延迟期。延迟后执行Runnable


或者你可以使用:

1
android.os.SystemClock.sleep(checkEvery)

它的优点是不需要包装。


这是我的例子

创建Java UTLS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    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();  

        }

    }


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

1
2
3
4
5
6
7
8
9
10
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网站

希望这能帮助别人…


如果你使用Kotlin和Coroutine,你只需

1
2
3
4
GlobalScope.launch {
   delay(3000) // In ms
   //Code after sleep
}

如果你需要更新用户界面

1
2
3
4
5
6
GlobalScope.launch {
  delay(3000)
  GlobalScope.launch(Dispatchers.Main) {
    //Action on UI thread
  }
}