Reputation: 77596
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
}
Upvotes: 921
Views: 861501
Reputation: 578
android.os.Handler(Looper.getMainLooper()).postDelayed({
// This block will run after 100ms
}, 100)
// In a background thread
try {
Thread.sleep(100)
} catch (e: InterruptedException) {
// recommended because catching InterruptedException clears interrupt flag
Thread.currentThread().interrupt()
// you probably want to quit if the thread is interrupted
return
}
// Code next to this line will run after 100ms
final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
// This block will run after 100ms
}
}, 100);
// In a background thread
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// recommended because catching InterruptedException clears interrupt flag
Thread.currentThread().interrupt();
// you probably want to quit if the thread is interrupted
return;
}
// Code next to this line will run after 100ms
Upvotes: 1
Reputation: 178
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()
}
Upvotes: 1
Reputation: 4791
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"
Upvotes: 26
Reputation: 26685
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);
The class to import is android.os.handler
.
Upvotes: 2202
Reputation: 818
Another response (java8) on activity class.
//hide with delay
new Thread(() -> {
try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}
this.runOnUiThread(() -> {
myView.setVisibility(View.GONE);//this run on GUI
});
}).start();
Upvotes: 0
Reputation: 5325
example:
Timer().schedule(500) {
activity?.runOnUiThread {
// code
}
}
Upvotes: 2
Reputation: 1095
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);
Upvotes: 4
Reputation: 8776
Well, you can always use legacy Thread.sleep()
if you are using Java.
new Thread(() -> {
try {
Thread.sleep(millis); //delay in milliseconds
} catch (Exception e) {
e.printStackTrace();
}
yourMethod();
}).start();
The only problem here is that you cannot do any UI updates since its a separate thread.
Upvotes: 0
Reputation: 11939
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);
Upvotes: 373
Reputation: 7113
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);
}
});
Upvotes: 45
Reputation: 2670
Using Kotlin, we can achieve by doing the following
Handler().postDelayed({
// do something after 1000ms
}, 1000)
Upvotes: 4
Reputation: 1018
There are a lot of ways to do this but the best is to use handler like below
long millisecDelay=3000
Handler().postDelayed({
// do your work here
},millisecDelay)
Upvotes: 0
Reputation: 41
In Android, we can write below kotlin code for delay execution of any function
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()
}
}
Upvotes: 0
Reputation: 23384
Similar solution but much cleaner to use
Write this function out side of class
fun delay(duration: Long, `do`: () -> Unit) {
Handler().postDelayed(`do`, duration)
}
Usage:
delay(5000) {
//Do your work here
}
Upvotes: 0
Reputation: 1499
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
Upvotes: 6
Reputation: 58934
Kotlin
&Java
Many Ways
Handler
Handler().postDelayed({
TODO("Do something")
}, 2000)
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")
}
Executors
Executors.newSingleThreadScheduledExecutor().schedule({
TODO("Do something")
}, 2, TimeUnit.SECONDS)
In Java
Handler
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something
}
}, 2000);
Timer
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// Do something
}
}, 2000);
ScheduledExecutorService
private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
Runnable runnable = new Runnable() {
public void run() {
// Do something
}
};
worker.schedule(runnable, 2, TimeUnit.SECONDS);
Upvotes: 55
Reputation: 35987
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);
Upvotes: 13
Reputation: 40126
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);
Upvotes: 3
Reputation: 13292
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);
Upvotes: 2
Reputation: 5392
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}")
}
}
Upvotes: 7
Reputation: 19824
Here is the answer in Kotlin you lazy, lazy people:
Handler().postDelayed({
//doSomethingHere()
}, 1000)
Upvotes: 1
Reputation: 330
You can make it much cleaner by using the newly introduced lambda expressions:
new Handler().postDelayed(() -> {/*your code here*/}, time);
Upvotes: 5
Reputation: 879
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.
Upvotes: 1
Reputation: 1690
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
Upvotes: 5
Reputation: 9142
I prefer to use View.postDelayed()
method, simple code below:
mView.postDelayed(new Runnable() {
@Override
public void run() {
// Do something after 1000 ms
}
}, 1000);
Upvotes: 19
Reputation: 10212
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.
Upvotes: 1
Reputation: 4108
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();
Upvotes: 2
Reputation: 2920
Here is my shortest solution:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
Upvotes: 15
Reputation: 269627
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);
⋮
}
Upvotes: 189
Reputation: 12333
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");
Upvotes: 3