科特林
Handler(Looper.getMainLooper()).postDelayed({
//Do something after 100ms
}, 100)
爪哇
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
在我的情况下,我无法使用任何其他答案。我改用本机 java Timer。
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// this code will be executed after 2 seconds
}
}, 2000);
注意:当问题没有将 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);
⋮
}
worker.schedule()
返回的 ScheduledFuture<?>
的引用并调用其 cancel(boolean)
方法。
ScheduledExecutorService
上的一个方法。
用于在 5 秒后在 UI 线程中执行某些操作:
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
//Do something here
}
}, 5000);
Kotlin 和 Java 多种方式
1.使用处理程序
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.newSingleThreadScheduledExecutor().schedule({
TODO("Do something")
}, 2, TimeUnit.SECONDS)
在 Java 中
1.使用处理程序
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something
}
}, 2000);
2. 使用定时器
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);
How to call a method after a delay in Android
。所以我专注于此。说到点子上了。否则,Java 泄漏对于开发人员来说是一个需要单独理解的大话题。
Handler().postDelayed({ }, 2000)
显示为已删除
你可以在 UIThread 中使用 Handler:
runOnUiThread(new Runnable() {
@Override
public void run() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//add your code here
}
}, 1000);
}
});
感谢所有出色的答案,我找到了最适合我需求的解决方案。
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
}
}
看这个演示:
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?");
}
}
如果您必须使用 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);
}
});
看起来很乱,但这是其中一种方式。
我更喜欢使用 View.postDelayed()
方法,下面的简单代码:
mView.postDelayed(new Runnable() {
@Override
public void run() {
// Do something after 1000 ms
}
}, 1000);
更安全 - 使用 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()
}
如果您收到未找到生命周期范围的错误! - 将此依赖项导入应用程序 gradle 文件:
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
这是我最短的解决方案:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
如果您使用的是 Android Studio 3.0 及更高版本,则可以使用 lambda 表达式。 2 秒后调用方法 callMyMethod()
:
new Handler().postDelayed(() -> callMyMethod(), 2000);
如果您需要取消延迟的可运行,请使用以下命令:
Handler handler = new Handler();
handler.postDelayed(() -> callMyMethod(), 2000);
// When you need to cancel all your posted runnables just use:
handler.removeCallbacksAndMessages(null);
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);
所以这里有一些事情需要考虑,因为有很多方法可以给这只猫剥皮。虽然答案都已经给出了选择和选择。我认为重要的是通过适当的编码指南重新审视这一点,以避免任何人仅仅因为“多数选择简单答案”而走错方向。
因此,首先让我们讨论简单的 Post Delayed 答案,它是该线程中的获胜者选择的答案。
有几件事需要考虑。在 post 延迟之后,您可能会遇到内存泄漏、死对象、已经消失的生命周期等等。所以正确处理也很重要。你可以通过几种方式做到这一点。
为了现代发展,我将在 KOTLIN 中提供
这是一个在回调上使用 UI 线程的简单示例,并在您点击回调时确认您的 Activity 仍然存在且运行良好。
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}")
}
}
对于简单的线处理后延迟,您可以执行以下操作:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// Do someting
}
}, 3000);
我希望这有帮助
您可以将其用于最简单的解决方案:
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
您可以使用新引入的 lambda 表达式使其更简洁:
new Handler().postDelayed(() -> {/*your code here*/}, time);
使用 Kotlin,我们可以通过执行以下操作来实现
Handler().postDelayed({
// do something after 1000ms
}, 1000)
如果您使用 RxAndroid,那么线程和错误处理会变得更加容易。以下代码在延迟后执行
Observable.timer(delay, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aLong -> {
// Execute code here
}, Throwable::printStackTrace);
我创建了更简单的方法来调用它。
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");
performSelector
。这是最好的方法。
当你得到以下一个作品时,
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);
使用 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();
我喜欢更干净的东西:这是我的实现,在您的方法中使用的内联代码
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
每个人似乎都忘记在 Handler 上发布新的可运行文件或消息之前对其进行清理。否则,它们可能会累积并导致不良行为。
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.
这是另一个棘手的方法:当可运行更改 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));
动画可以附加到任何视图。
科特林
片段中的 runOnUiThread
定时器
例子:
Timer().schedule(500) {
activity?.runOnUiThread {
// code
}
}
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
}
}
Handler
上调用removeCallbacks(Runnable r)
来取消执行,只要 Runnable 仍在消息队列中。import android.os.handler