如何在Android中延迟调用一个方法

908

我希望能在指定的延迟时间后调用下面的方法。 在Objective-C中,有一个类似于以下代码的方法:

[self performSelector:@selector(DoSomething) withObject:nil afterDelay:5];

在安卓Java中是否有此方法的等效方法?例如,我需要在5秒后调用一个方法。

public void DoSomething()
{
     //do something here
}
36个回答

4
如果您使用RxAndroid,线程和错误处理将变得更加容易。以下代码会在延迟后执行。
Observable.timer(delay, TimeUnit.SECONDS)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(aLong -> {
            // Execute code here
        }, Throwable::printStackTrace);

3

我创建了一个更简单的方法来调用它。

public static void CallWithDelay(long miliseconds, final Activity activity, final String methodName)
    {
        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                try {
                    Method method =  activity.getClass().getMethod(methodName);
                    method.invoke(activity);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }, miliseconds);
    }

要使用它,只需调用:.CallWithDelay(5000, this, "DoSomething");

3
这么基本的任务需要反思吗? - Max Ch
由于问题类似于 iOS 的 performSelector 方法的调用,这是最好的方法。 - HelmiB

3
当您遇到以下错误时,可以尝试下列解决方法:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
解决方法如下:
在子线程中使用Handler发送消息之前,需要先调用Looper.prepare()方法来为该线程创建一个消息队列。这样才能保证在该线程中使用Handler正常工作。
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
  @Override
  public void run() {
    //Do something after 100ms
  }
}, 100);

2

我喜欢事情更加简洁:

这是我的实现,内联代码可在您的方法中使用

new Handler().postDelayed(new Runnable() {
  @Override
  public void run() {
    //Do something after 100ms
  }
}, 100);

2

使用CountDownTimer非常容易。 更多细节请参考https://developer.android.com/reference/android/os/CountDownTimer.html

import android.os.CountDownTimer;

// calls onTick every second, finishes after 3 seconds
new CountDownTimer(3000, 1000) { 

   public void onTick(long millisUntilFinished) {
      Log.d("log", millisUntilFinished / 1000);
   }

   public void onFinish() {
      // called after count down is finished
   } 
}.start();

1

1
这里有另一种巧妙的方法:当可运行对象更改UI元素时,它不会抛出异常。
public class SimpleDelayAnimation extends Animation implements Animation.AnimationListener {

    Runnable callBack;

    public SimpleDelayAnimation(Runnable runnable, int delayTimeMilli) {
        setDuration(delayTimeMilli);
        callBack = runnable;
        setAnimationListener(this);
    }

    @Override
    public void onAnimationStart(Animation animation) {

    }

    @Override
    public void onAnimationEnd(Animation animation) {
        callBack.run();
    }

    @Override
    public void onAnimationRepeat(Animation animation) {

    }
}

您可以这样调用动画:

view.startAnimation(new SimpleDelayAnimation(delayRunnable, 500));

动画可以附加到任何视图。


1
  • Kotlin
  • 在Fragment中使用runOnUiThread
  • 定时器

例子:

Timer().schedule(500) {
    activity?.runOnUiThread {
        // code                                    
    }
}

1
每个人似乎都忘记在发布新的可运行对象或消息之前清理处理程序。否则,它们可能会累积并导致不良行为。
handler.removeMessages(int what);
// Remove any pending posts of messages with code 'what' that are in the message queue.

handler.removeCallbacks(Runnable r)
// Remove any pending posts of Runnable r that are in the message queue.

1
在这种情况下,如果你对UI进行了一些改变,那么你应该使用viewLifecycleOwner的lifecycleScope,因为在销毁Activity/Fragment的情况下,这个操作是安全的,不会执行,否则如果没有viewLifecycleOwner,当修改与任何东西都没有绑定的UI时,应用程序将崩溃。
private val DELAY_MS = 5000

viewLifecycleOwner.lifecycleScope.launch {
   delay(DELAY_MS)
   doSomething()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接