如何在Android延迟后调用方法

时间:2010-06-18 18:24:19

标签: java android handler delay

我希望能够在指定的延迟后调用以下方法。  在目标c中有类似的东西:

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

在android中有与java相同的方法吗? 例如,我需要能够在5秒后调用一个方法。

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

32 个答案:

答案 0 :(得分:1651)

科特林

Handler().postDelayed({
  //Do something after 100ms
}, 100)


爪哇

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


答案 1 :(得分:291)

在我的案例中,我无法使用任何其他答案。 我使用了原生的Java Timer。

new Timer().schedule(new TimerTask() {          
    @Override
    public void run() {
        // this code will be executed after 2 seconds       
    }
}, 2000);

答案 2 :(得分:180)

注意:当问题未指定Android作为上下文时,会给出此答案。有关Android UI线程look here.

的特定答案

看起来Mac OS API允许当前线程继续,并安排任务以异步方式运行。在Java中,等效函数由java.util.concurrent包提供。我不确定Android可能会施加什么限制。

private static final ScheduledExecutorService worker = 
  Executors.newSingleThreadScheduledExecutor();

void someMethod() {
  ⋮
  Runnable task = new Runnable() {
    public void run() {
      /* Do something… */
    }
  };
  worker.schedule(task, 5, TimeUnit.SECONDS);
  ⋮
}

答案 3 :(得分:95)

用于在5秒后在UI线程中执行某些操作:

new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
    @Override
    public void run() {
        //Do something here
    }
}, 5000);

答案 4 :(得分:38)

你可以在UIThread中使用Handler:

runOnUiThread(new Runnable() {

    @Override
    public void run() {
         final Handler handler = new Handler();
         handler.postDelayed(new Runnable() {
           @Override
           public void run() {
               //add your code here
           }
         }, 1000);

    }
});

答案 5 :(得分:36)

感谢所有出色的答案,我找到了最适合我需求的解决方案。

Handler myHandler = new DoSomething();
Message m = new Message();
m.obj = c;//passing a parameter here
myHandler.sendMessageDelayed(m, 1000);

class DoSomething extends Handler {
    @Override
    public void handleMessage(Message msg) {
      MyObject o = (MyObject) msg.obj;
      //do something here
    }
}

答案 6 :(得分:21)

参见此演示:

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?");
     }
}

答案 7 :(得分:21)

如果必须使用Handler,但是您正在使用另一个线程,则可以使用runonuithread在UI线程中运行处理程序。这样可以避免因要求调用Looper.Prepare()

而引发的例外情况
runOnUiThread(new Runnable() {
    @Override
    public void run() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //Do something after 1 second
            }
        }, 1000);
    }
});

看起来很乱,但这是其中之一。

答案 8 :(得分:16)

我更喜欢使用View.postDelayed()方法,下面是简单的代码:

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

答案 9 :(得分:13)

这是我最简短的解决方案:

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

答案 10 :(得分:10)

final Handler handler = new Handler(); 
Timer t = new Timer(); 
t.schedule(new TimerTask() { 
    public void run() { 
        handler.post(new Runnable() { 
            public void run() { 
                //DO SOME ACTIONS HERE , THIS ACTIONS WILL WILL EXECUTE AFTER 5 SECONDS...
            }
        }); 
    } 
}, 5000); 

答案 11 :(得分:8)

如果您使用 Android Studio 3.0 及更高版本,则可以使用lambda表达式。方法callMyMethod()在2秒后调用:

new Handler().postDelayed(() -> callMyMethod(), 2000);

如果你需要取消延迟的runnable,请使用:

Handler handler = new Handler();
handler.postDelayed(() -> callMyMethod(), 2000);

// When you need to cancel all your posted runnables just use:
handler.removeCallbacksAndMessages(null);

答案 12 :(得分:7)

更安全 - 使用 Kotlin

大多数答案都使用 Handler,但我给出了一个不同的解决方案来延迟活动、片段、使用 Android Lifecycle ext 的视图模型。这种方式会在生命周期开始销毁时自动取消。

在活动或片段中:

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

在视图模型中:

viewModelScope.lanch {
  delay(DELAY_MS)
  doSomething()
}

挂起函数:(Kotlin Coroutine)

suspend fun doSomethingAfter(){
    delay(DELAY_MS)
    doSomething()
}

如果您遇到 lifecycleScope not found 的错误 - 导入到 gradle 文件:

implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"

答案 13 :(得分:6)

我建议使用Timer,它允许您安排在非常特定的时间间隔内调用的方法。这不会阻止您的UI,并且在执行方法时保持您的应用程序的响应性。

另一个选项是wait();方法,这将阻止当前线程达到指定的时间长度。如果您在UI线程上执行此操作,这将导致UI停止响应。

答案 14 :(得分:6)

  

KotlinJava多种方式

1。使用Handler

Handler().postDelayed({
    TODO("Do something")
    }, 2000)

2。使用TimerTask

Timer().schedule(object : TimerTask() {
    override fun run() {
        TODO("Do something")
    }
}, 2000)

或更短

Timer().schedule(timerTask {
    TODO("Do something")
}, 2000)

或者最短的应该是

Timer().schedule(2000) {
    TODO("Do something")
}

3。使用Executors

Executors.newSingleThreadScheduledExecutor().schedule({
    TODO("Do something")
}, 2, TimeUnit.SECONDS)
  

在Java中

1。使用Handler

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

2。使用Timer

new Timer().schedule(new TimerTask() {          
    @Override
    public void run() {
        // Do something
    }
}, 2000);

3。使用ScheduledExecutorService

private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();

Runnable runnable = new Runnable() {
  public void run() {
      // Do something
  }
  };
worker.schedule(runnable, 2, TimeUnit.SECONDS);

答案 15 :(得分:5)

您可以将此用于最简单的解决方案:

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

答案 16 :(得分:4)

使用新引入的lambda表达式可以使它更清晰:

new Handler().postDelayed(() -> {/*your code here*/}, time);

答案 17 :(得分: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");

答案 18 :(得分:3)

当您获得以下作品时,

  

java.lang.RuntimeException:无法在该线程内部创建处理程序   尚未调用Looper.prepare()

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

答案 19 :(得分:2)

这里有很多事情要考虑,因为有很多方法可以给这只猫换皮。尽管答案已经全部选定。我认为重要的是要重新使用适当的编码准则,以避免任何人仅仅因为“多数人选择了简单答案”而走错了方向。

因此,首先让我们讨论简单的“延迟发布”答案,这是该主题中获胜者整体选择的答案。

需要考虑的几件事。发布延迟之后,您可能会遇到内存泄漏,死对象,已经消失的生命周期等。因此,正确处理它也很重要。您可以通过以下两种方式完成此操作。

为了现代发展,我将在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
   }
}

如果将launch(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}")
            }
        }

答案 20 :(得分: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();

答案 21 :(得分:2)

对于简单的行句柄延迟,您可以执行以下操作:

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        // Do someting
    }
}, 3000);

我希望这对您有帮助

答案 22 :(得分:1)

每个人似乎忘记在发布新的runnable或消息之前清理Handler。否则,它们可能会累积并导致不良行为。

{{1}}

答案 23 :(得分:1)

Here is the answer在科特林,你是个懒惰的人:

Handler().postDelayed({
//doSomethingHere()
}, 1000)

答案 24 :(得分:1)

我喜欢清洁的东西: 这是我的实现,在您的方法中使用的内联代码

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

答案 25 :(得分:1)

这是另一个棘手的方法:当runnable更改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));

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

答案 26 :(得分:0)

android中的合适解决方案:

private static long SLEEP_TIME = 2 // for 2 second
.
.
MyLauncher launcher = new MyLauncher();
            launcher.start();
.
.
private class MyLauncher extends Thread {
        @Override
        /**
         * Sleep for 2 seconds as you can also change SLEEP_TIME 2 to any. 
         */
        public void run() {
            try {
                // Sleeping
                Thread.sleep(SLEEP_TIME * 1000);
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
            //do something you want to do
           //And your code will be executed after 2 second
        }
    }

答案 27 :(得分:0)

如果使用RxAndroid,则线程和错误处理将变得更加容易。延迟后执行以下代码

.strip

答案 28 :(得分:0)

类似的解决方案,但使用起来更清洁

将此函数写在类之外

fun delay(duration: Long, `do`: () -> Unit) {

    Handler().postDelayed(`do`, duration)

}

用法:

delay(5000) {
    //Do your work here
}

答案 29 :(得分:0)

在Android中,我们可以在kotlin下面编写代码,以延迟执行任何功能

class MainActivity : AppCompatActivity() {

private lateinit var handler: Handler

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    handler= Handler()
    handler.postDelayed({
        doSomething()
    },2000)
}

private fun doSomething() {
    Toast.makeText(this,"Hi! I am Toast Message",Toast.LENGTH_SHORT).show()
}
}

答案 30 :(得分:0)

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

long millisecDelay=3000

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

答案 31 :(得分:0)

使用Kotlin,我们可以通过以下操作来实现

Handler().postDelayed({
    // do something after 1000ms 
}, 1000)