Android中如何在延迟后调用方法

发布于 2024-09-06 08:49:31 字数 297 浏览 9 评论 0原文

我希望能够在指定的延迟后调用以下方法。 在 Objective C 中,有类似这样的内容:

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

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

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

I want to be able to call the following method after a specified delay.
In objective c there was something like:

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

Is there an equivalent of this method in android with java?
For example I need to be able to call a method after 5 seconds.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

黎歌 2024-09-13 08:49:31

Kotlin

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

Java

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

要导入的类是 android.os.handler

Kotlin

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

Java

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

The class to import is android.os.handler.

微凉 2024-09-13 08:49:31

我无法在我的案例中使用任何其他答案。
我使用了原生的 java Timer 来代替。

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

I couldn't use any of the other answers in my case.
I used the native java Timer instead.

new Timer().schedule(new TimerTask() {          
    @Override
    public void run() {
        // this code will be executed after 2 seconds       
    }
}, 2000);
海风掠过北极光 2024-09-13 08:49:31

注意:当问题未指定 Android 作为上下文时给出此答案。对于特定于 Android UI 线程的答案查看此处。


看起来 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);
  ⋮
}

Note: This answer was given when the question didn't specify Android as the context. For an answer specific to the Android UI thread look here.


It looks like the Mac OS API lets the current thread continue, and schedules the task to run asynchronously. In the Java, the equivalent function is provided by the java.util.concurrent package. I'm not sure what limitations Android might impose.

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

void someMethod() {
  ⋮
  Runnable task = new Runnable() {
    public void run() {
      /* Do something… */
    }
  };
  worker.schedule(task, 5, TimeUnit.SECONDS);
  ⋮
}
活泼老夫 2024-09-13 08:49:31

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

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

For executing something in the UI Thread after 5 seconds:

new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
    @Override
    public void run() {
        //Do something here
    }
}, 5000);
画离情绘悲伤 2024-09-13 08:49:31

Kotlin & Java多种方式

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);

Kotlin & Java Many Ways

1. Using Handler

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

2. Using TimerTask

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

Or even shorter

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

Or shortest would be

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

3. Using Executors

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

In Java

1. Using Handler

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

2. Using Timer

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

3. Using ScheduledExecutorService

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

Runnable runnable = new Runnable() {
  public void run() {
      // Do something
  }
  };
worker.schedule(runnable, 2, TimeUnit.SECONDS);
狼性发作 2024-09-13 08:49:31

您可以在 UIThread 中使用 Handler:

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

you can use Handler inside UIThread:

runOnUiThread(new Runnable() {
                
    @Override
    public void run() {
        new Handler().postDelayed(new Runnable() {
           @Override
           public void run() {
               //add your code here
          }
        }, 1000);           
    }
});
稚然 2024-09-13 08:49:31

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

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
    }
}

Thanks for all the great answers, I found a solution that best suits my needs.

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
    }
}
于我来说 2024-09-13 08:49:31

更多安全性 - 使用 Kotlin 协程

大多数答案都使用 Handler,但我提供了一种不同的解决方案来使用 Android 生命周期扩展来处理活动、片段和视图模型中的延迟。 此方法会在生命周期销毁时自动取消,避免内存泄漏或应用崩溃

在 Activity 或 Fragment 中:

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

在 ViewModel 中:

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

在挂起函数:(Kotlin 协程)

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

如果您收到 lifecycleScope not find! 的错误! - 将此依赖项导入到应用程序 gradle 文件中:

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

More Safety - With Kotlin Coroutine

Most of the answers use Handler, but I provide a different solution to handle delays in activity, fragment, and view model using Android Lifecycle extensions. This approach will automatically cancel when the lifecycle is destroyed, avoiding memory leaks or app crashes

In Activity or Fragment:

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

In ViewModel:

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

In suspend function: (Kotlin Coroutine)

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

If you get an error with the lifecycleScope not found! - import this dependency to the app gradle file:

implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
橘虞初梦 2024-09-13 08:49:31

看这个演示:

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

See this demo:

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?");
     }
}
凉城已无爱 2024-09-13 08:49:31

如果您必须使用 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);
    }
});

看起来很混乱,但这是方法之一。

If you have to use the Handler, but you are into another thread, you can use runonuithread to run the handler in UI thread. This will save you from Exceptions thrown asking to call Looper.Prepare()

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //Do something after 1 second
            }
        }, 1000);
    }
});

Looks quite messy, but this is one of the way.

迷途知返 2024-09-13 08:49:31

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

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

I prefer to use View.postDelayed() method, simple code below:

mView.postDelayed(new Runnable() {
    @Override
    public void run() {
        // Do something after 1000 ms
    }
}, 1000);
自在安然 2024-09-13 08:49:31

这是我的最短解决方案:

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

Here is my shortest solution:

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        //Do something after 100ms
    }
}, 100);
小伙你站住 2024-09-13 08:49:31

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

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);

If you are using Android Studio 3.0 and above you can use lambda expressions. The method callMyMethod() is called after 2 seconds:

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

In case you need to cancel the delayed runnable use this:

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

// When you need to cancel all your posted runnables just use:
handler.removeCallbacksAndMessages(null);
2024-09-13 08:49:31
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); 
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); 
吻泪 2024-09-13 08:49:31

我建议 计时器,它允许您安排一个在非常特定的时间间隔调用的方法。这不会阻塞您的 UI,并在执行该方法时使您的应用程序保持响应。

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

I suggest the Timer, it allows you to schedule a method to be called on a very specific interval. This will not block your UI, and keep your app resonsive while the method is being executed.

The other option, is the wait(); method, this will block the current thread for the specified length of time. This will cause your UI to stop responding if you do this on the UI thread.

陈年往事 2024-09-13 08:49:31

因此,这里需要考虑一些事情,因为给这只猫剥皮的方法有很多。虽然答案都已经给出了选择和选择。我认为重要的是,用适当的编码指南重新审视这一点,以避免任何人仅仅因为“大多数选择的简单答案”而走上错误的方向。

因此,首先让我们讨论简单的延迟后答案,这是该线程中总体获胜者选择的答案。

有几点需要考虑。延迟后,您可能会遇到内存泄漏、死对象、生命周期消失等问题。所以正确处理它也很重要。您可以通过几种方式来做到这一点。

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

//handle cleanup

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

So there are a few things to consider here as there are so many ways to skin this cat. Although answers have all already been given selected and chosen. I think it's important that this gets revisited with proper coding guidelines to avoid anyone going the wrong direction just because of "majority selected simple answer".

So first let's discuss the simple Post Delayed answer that is the winner selected answer overall in this thread.

A couple of things to consider. After the post delay, you can encounter memory leaks, dead objects, life cycles that have gone away, and more. So handling it properly is important as well. You can do this in a couple of ways.

For sake of modern development, I'll supply in KOTLIN

Here is a simple example of using the UI thread on a callback and confirming that your activity is still alive and well when you hit your callback.

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

However, this is still not perfect as there is no reason to hit your callback if the activity has gone away. so a better way would be to keep a reference to it and remove it's callbacks like this.

    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)
        }
    }

and of course handle cleanup on the onPause so it doesn't hit the callback.

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

Now that we have talked through the obvious, let's talk about a cleaner option with modern day coroutines and kotlin :). If you aren't using these yet, you are really missing out.

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

or if you want to always do a UI launch on that method you can simply do:

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

Of course just like the PostDelayed you have to make sure you handle canceling so you can either do the activity checks after the delay call or you can cancel it in the onPause just like the other route.

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

//handle cleanup

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
   }
}

If you put the launch(UI) into the method signature the job can be assigned in the calling line of code.

so moral of the story is to be safe with your delayed actions, make sure you remove your callbacks, or cancel your jobs and of course confirm you have the right life cycle to touch items on your delay callback complete. The Coroutines also offers cancelable actions.

Also worth noting that you should typically handle the various exceptions that can come with coroutines. For example, a cancelation, an exception, a timeout, whatever you decide to use. Here is a more advanced example if you decide to really start utilizing coroutines.

   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}")
            }
        }
待天淡蓝洁白时 2024-09-13 08:49:31

对于简单的线路处理后延迟,您可以执行以下操作:

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

我希望这有帮助

For a Simple line Handle Post delay, you can do as following :

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

I hope this helps

裂开嘴轻声笑有多痛 2024-09-13 08:49:31

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

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

You can use this for Simplest Solution:

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

Else, Below can be another clean useful solution:

new Handler().postDelayed(() -> 
{/*Do something here*/}, 
5000); //time in ms
囚我心虐我身 2024-09-13 08:49:31

您可以使用新引入的 lambda 表达式使其更加简洁:

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

You can make it much cleaner by using the newly introduced lambda expressions:

new Handler().postDelayed(() -> {/*your code here*/}, time);
只有影子陪我不离不弃 2024-09-13 08:49:31

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

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

Using Kotlin, we can achieve by doing the following

Handler().postDelayed({
    // do something after 1000ms 
}, 1000)
暮年慕年 2024-09-13 08:49:31

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

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

If you use RxAndroid then thread and error handling becomes much easier. Following code executes after a delay

Observable.timer(delay, TimeUnit.SECONDS)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(aLong -> {
            // Execute code here
        }, Throwable::printStackTrace);
风尘浪孓 2024-09-13 08:49:31

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

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

I created simpler method to call this.

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

To use it, just call : .CallWithDelay(5000, this, "DoSomething");

无所谓啦 2024-09-13 08:49:31

当你得到下面的一个作品时,

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);

Below one works when you get,

java.lang.RuntimeException: Can't create handler inside thread that
has not called Looper.prepare()

final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
  @Override
  public void run() {
    //Do something after 100ms
  }
}, 100);
久而酒知 2024-09-13 08:49:31

使用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();

It's very easy using the CountDownTimer.
For more details 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();
沉溺在你眼里的海 2024-09-13 08:49:31

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

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

I like things cleaner:
Here is my implementation, inline code to use inside your method

new Handler().postDelayed(new Runnable() {
  @Override
  public void run() {
    //Do something after 100ms
  }
}, 100);
旧话新听 2024-09-13 08:49:31
  • 示例的Kotlin
  • 来自 Fragment
  • Timer

runOnUiThread :

Timer().schedule(500) {
    activity?.runOnUiThread {
        // code                                    
    }
}
  • Kotlin
  • runOnUiThread from a Fragment
  • Timer

example:

Timer().schedule(500) {
    activity?.runOnUiThread {
        // code                                    
    }
}
川水往事 2024-09-13 08:49:31

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

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.

everybody seems to forget to clean the Handler before posting a new runnable or message on it. Otherway they could potentially accumulate and cause bad behaviour.

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.
我为君王 2024-09-13 08:49:31

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

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

Here is another tricky way: it won't throw exception when the runnable change UI elements.

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) {

    }
}

You can call the animation like this:

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

Animation can attach to any view.

狼性发作 2024-09-13 08:49:31

这是 Kotlin 中的答案,你们这些懒惰的人:

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

Here is the answer in Kotlin you lazy, lazy people:

Handler().postDelayed({
//doSomethingHere()
}, 1000)
心清如水 2024-09-13 08:49:31

Activity/Fragment - 在这种情况下如果您对UI进行了更改,那么您应该使用viewLifecycleOwnerlifecycleScope因为在销毁 Activity/Fragment 的情况下,此操作将是安全的并且不会执行,否则如果没有 viewLifecycleOwner,应用程序将在修改未绑定到任何内容的 UI 时崩溃。

private val DELAY_MS = 5000

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

Activity/Fragment - in this case if you doSomething with UI changes, then you should use viewLifecycleOwner's lifecycleScope because in the case of destroying the Activity/Fragment this operation is going to be safe and is not to execute, otherwise without viewLifecycleOwner the app will crash when modifying the UI that would be not bound to anything.

private val DELAY_MS = 5000

viewLifecycleOwner.lifecycleScope.launch {
   delay(DELAY_MS)
   doSomething()
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文