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

Hub*_*ert 284 multithreading android process

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

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

thisbutton.setBackgroundResource(R.drawable.icon);
Run Code Online (Sandbox Code Playgroud)

- >让我们说1秒后,我需要通过改变它的背景来回到按钮的先前状态:

thisbutton.setBackgroundResource(R.drawable.defaultcard);
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

new Reminder(5);
Run Code Online (Sandbox Code Playgroud)

有了这个:

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
            }
        }  
    }
Run Code Online (Sandbox Code Playgroud)

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

tro*_*man 444

解决此问题的一种方法是使用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); 
}
Run Code Online (Sandbox Code Playgroud)

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

一个更复杂的解决方案,避免内存泄漏,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);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 2年后,这段代码刚刚帮助了我!谢谢@tronman !! :) (26认同)
  • 我不确定你的意思是"不方便".Handler的postDelayed方法旨在告诉Android您需要在经过一定时间后执行一些代码. (4认同)
  • 它有效,但这是一种在代码中引入延迟的非常不方便的方法,对吗? (3认同)
  • 您可以简单地将其复制到另一个(最终)变量,如此最终的按钮mynewbutton = mybutton;`并在Handler和Runnable中使用`mynewbutton`. (2认同)
  • @MelvinLai 5年后,这段代码只是帮助了我!:) (2认同)

Daw*_*ozd 183

你可以尝试这个很短的

SystemClock.sleep(7000);
Run Code Online (Sandbox Code Playgroud)

警告:永远不要在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);
            }
        });
Run Code Online (Sandbox Code Playgroud)

没有创建tmp Handler.此解决方案也优于@tronman,因为我们不会保留Handler的视图.我们也没有在坏线程中创建Handler的问题;)

文档

public static void sleep(long ms)

在API级别1中添加

在返回之前等待给定的毫秒数(uptimeMillis).类似于sleep(long),但不会抛出InterruptedException ; interrupt()事件被推迟到下一个可中断操作.难道不返回直到至少指定的毫秒数已过时.

参数

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

从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;
}
Run Code Online (Sandbox Code Playgroud)

  • OMG当然在后台线程中这样做. (76认同)
  • 让Android UI冻结?不要这样做. (22认同)
  • Gelldur,你错过了@ RichieHH评论的观点.与你发布**之前3年接受的**答案相比,你的建议并没有帮助OP解决他的问题.原因:代码,如OP所示,并且如接受的答案所示,**在UI处理程序**中运行.说"OMG当然在后台线程中执行此操作"是无关紧要的,除非你展示如何将它放在后台线程中.在那个时候,您会发现答案比已经接受的答案更复杂.我是否提到三年前接受了更好的解决方案?:P (13认同)
  • Ctrl + Shift + O(Eclipse自动导入) (3认同)
  • ...忘了提到使这个建议特别偏离问题的原因是,OP明确要在延迟后做UI操作.所以,你会有一个解决方案,你已经创建了一个后台线程(已经比解决问题所需的更重),睡觉了,然后你必须(以某种方式)回到UI线程.`Handler + postRunnable`只需一步即可完成所有这些工作.没有创建第二个线程的系统开销. (2认同)
  • @ToolmakerSteve 现在很开心:D?主要问题是:“如何在 Android 中暂停/休眠线程或进程?” 所以我的回答很简单:)。如果有人在谷歌上搜索“如何睡眠线程”,则会显示此问题。他/她可能正在寻找我的答案:P。但是好的,我添加了完整的回复;) (2认同)

小智 25

我用这个:

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

  • 什么是`e.getLocalizedMessage()`应该做什么? (4认同)

Dan*_*sky 16

你可能不希望这样做.通过sleep()在按钮单击的事件处理程序中显式显示,您实际上会锁定整个UI一秒钟.一种选择是使用某种单次定时器.创建一个TimerTask以将背景颜色更改回默认颜色,并在Timer上安排它.

另一种可能性是使用Handler.有一个关于从使用Timer切换到使用Handler的人的教程.

顺便说一下,你不能暂停一个过程.Java(或Android)进程至少有一个线程,您只能睡眠线程.


小智 14

我使用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(); 
Run Code Online (Sandbox Code Playgroud)


Hub*_*ert 9

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

@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); 
    }
Run Code Online (Sandbox Code Playgroud)

  • 为什么不postDelayed?无需计时器. (2认同)

Com*_*are 8

除了Yankowsky先生的答案,你也可以使用postDelayed().这可以在任何View(例如,您的卡)上使用,并且需要Runnable一段延迟时间.它执行Runnable延迟之后.


小智 5

这是我的例子

创建 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();  

        }

    }    
Run Code Online (Sandbox Code Playgroud)

  • 在问题已经很好地解决多年之后,另一个答案补充道,这与问题无关,因为它没有处理能够执行 UI 工作的既定愿望。你不能在这里做 UI 工作,因为你正在一个新线程上运行。不在 UI 线程上。 (3认同)

小智 5

或者你可以使用:

android.os.SystemClock.sleep(checkEvery)
Run Code Online (Sandbox Code Playgroud)

它的优点是不需要包装try ... catch