我希望能够在指定的延迟后调用以下方法。 在objective c中,有这样的东西:

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

在android和java中是否有类似的方法? 例如,我需要能够在5秒后调用一个方法。

public void DoSomething()
{
     //do something here
}

当前回答

所以这里有几件事要考虑,因为有这么多方法来剥这只猫的皮。尽管答案都已经给出了。我认为重要的是,要用适当的编码指南重新审视这个问题,以避免任何人仅仅因为“多数选择的简单答案”而走向错误的方向。

因此,首先让我们讨论一下简单的Post Delayed answer,这是在这个线程中胜出的答案。

有几件事需要考虑。在post延迟之后,您可能会遇到内存泄漏、死对象、生命周期消失等等。所以正确处理也很重要。有几种方法可以做到这一点。

为了现代发展,我将在KOTLIN供应

下面是一个简单的例子,在回调中使用UI线程,并在你点击回调时确认你的活动仍然活跃。

  Handler(Looper.getMainLooper()).postDelayed({
            if(activity != null && activity?.isFinishing == false){
                txtNewInfo.visibility = View.GONE
            }
        }, NEW_INFO_SHOW_TIMEOUT_MS)

然而,这仍然不是完美的,因为如果活动已经消失,没有理由点击你的回调。更好的方法是保留对它的引用并像这样删除它的回调。

    private fun showFacebookStylePlus1NewsFeedOnPushReceived(){
        A35Log.v(TAG, "showFacebookStylePlus1NewsFeedOnPushReceived")
        if(activity != null && activity?.isFinishing == false){
            txtNewInfo.visibility = View.VISIBLE
            mHandler.postDelayed({
                if(activity != null && activity?.isFinishing == false){
                    txtNewInfo.visibility = View.GONE
                }
            }, NEW_INFO_SHOW_TIMEOUT_MS)
        }
    }

当然在onPause上处理清理,这样它就不会碰到回调。

    override fun onPause() {
        super.onPause()
        mHandler.removeCallbacks(null)
    }

现在,我们已经讨论了显而易见的问题,让我们讨论一个使用现代协程和kotlin的更干净的选项:)。如果你还没有使用这些,你就真的错过了。

   fun doActionAfterDelay() 
        launch(UI) {
            delay(MS_TO_DELAY)           
            actionToTake()
        }
    }

或者如果你想总是在那个方法上做一个UI启动,你可以简单地做:

  fun doActionAfterDelay() = launch(UI){ 
      delay(MS_TO_DELAY)           
      actionToTake()
  }

当然,就像PostDelayed一样,你必须确保你处理取消,所以你可以在延迟调用后做活动检查,或者你可以像其他路由一样在onPause中取消它。

var mDelayedJob: Job? = null
fun doActionAfterDelay() 
   mDelayedJob = launch(UI) {
            try {
               delay(MS_TO_DELAY)           
               actionToTake()
            }catch(ex: JobCancellationException){
                showFancyToast("Delayed Job canceled", true, FancyToast.ERROR, "Delayed Job canceled: ${ex.message}")
            }
        }
   }
}

/ /处理清理

override fun onPause() {
   super.onPause()
   if(mDelayedJob != null && mDelayedJob!!.isActive) {
      A35Log.v(mClassTag, "canceling delayed job")
      mDelayedJob?.cancel() //this should throw CancelationException in coroutine, you can catch and handle appropriately
   }
}

如果您将启动(UI)放入方法签名中,作业可以在调用代码行中分配。

这个故事的寓意是要保证延迟操作的安全性,确保你删除了你的回调,或者取消了你的作业当然还要确认你有正确的生命周期去触摸你的延迟回调完成上的项。协程还提供了可取消的操作。

同样值得注意的是,您通常应该处理协程带来的各种异常。例如,取消、异常、超时,无论您决定使用什么。下面是一个更高级的示例,如果您决定真正开始使用协同程序。

   mLoadJob = launch(UI){
            try {
                //Applies timeout
                withTimeout(4000) {
                    //Moves to background thread
                    withContext(DefaultDispatcher) {
                        mDeviceModelList.addArrayList(SSDBHelper.getAllDevices())
                    }
                }

                //Continues after async with context above
                showFancyToast("Loading complete", true, FancyToast.SUCCESS)
            }catch(ex: JobCancellationException){
                showFancyToast("Save canceled", true, FancyToast.ERROR, "Save canceled: ${ex.message}")
            }catch (ex: TimeoutCancellationException) {
                showFancyToast("Timed out saving, please try again or press back", true, FancyToast.ERROR, "Timed out saving to database: ${ex.message}")
            }catch(ex: Exception){
                showFancyToast("Error saving to database, please try again or press back", true, FancyToast.ERROR, "Error saving to database: ${ex.message}")
            }
        }

其他回答

请看这个演示:

import java.util.Timer;
import java.util.TimerTask;

class Test {
     public static void main( String [] args ) {
          int delay = 5000;// in ms 

          Timer timer = new Timer();

          timer.schedule( new TimerTask(){
             public void run() { 
                 System.out.println("Wait, what..:");
              }
           }, delay);

           System.out.println("Would it run?");
     }
}

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

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,这个,"DoSomething");

有很多方法可以做到这一点,但最好的是使用如下处理程序

long millisecDelay=3000

Handler().postDelayed({
  // do your work here
 },millisecDelay)

如果你使用RxAndroid,那么线程和错误处理就会变得容易得多。以下代码在延迟后执行

Observable.timer(delay, TimeUnit.SECONDS)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(aLong -> {
            // Execute code here
        }, Throwable::printStackTrace);

你可以使用这个最简单的解决方案:

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        //Write your code here
    }
}, 5000); //Timer is in ms here.

否则,下面可能是另一个干净有用的解决方案:

new Handler().postDelayed(() -> 
{/*Do something here*/}, 
5000); //time in ms