aryaxt
aryaxt

Reputation: 77596

How to call a method after a delay in Android

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

Answers (30)

dev.tejasb
dev.tejasb

Reputation: 578

Kotlin

Main Thread
android.os.Handler(Looper.getMainLooper()).postDelayed({
    // This block will run after 100ms
}, 100)
Background Thread
// 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

Java

Main Thread
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);
Background Thread
// 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

radus14
radus14

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

Wilson Tran
Wilson Tran

Reputation: 4791

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"

Upvotes: 26

Arif Amirani
Arif Amirani

Reputation: 26685

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.

Upvotes: 2202

Barrrettt
Barrrettt

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

norbDEV
norbDEV

Reputation: 5325

  • Kotlin
  • runOnUiThread from a Fragment
  • Timer

example:

Timer().schedule(500) {
    activity?.runOnUiThread {
        // code                                    
    }
}

Upvotes: 2

Ashik
Ashik

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

Roshana Pitigala
Roshana Pitigala

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

Jules Colle
Jules Colle

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

Hossam Ghareeb
Hossam Ghareeb

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

Nikhil Katekhaye
Nikhil Katekhaye

Reputation: 2670

Using Kotlin, we can achieve by doing the following

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

Upvotes: 4

Shivam Yadav
Shivam Yadav

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

Ahasan
Ahasan

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

Manohar
Manohar

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

Mr T
Mr T

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

Khemraj Sharma
Khemraj Sharma

Reputation: 58934

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

Upvotes: 55

vovahost
vovahost

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

Sazzad Hissain Khan
Sazzad Hissain Khan

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

Thiago
Thiago

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

Sam
Sam

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

Daniel Wilson
Daniel Wilson

Reputation: 19824

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

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

Upvotes: 1

Alnour Alharin
Alnour Alharin

Reputation: 330

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

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

Upvotes: 5

cdytoby
cdytoby

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

Master_GoGo
Master_GoGo

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

codezjx
codezjx

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

Dan Alboteanu
Dan Alboteanu

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

Abdul Rizwan
Abdul Rizwan

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

Alecs
Alecs

Reputation: 2920

Here is my shortest solution:

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

Upvotes: 15

erickson
erickson

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

HelmiB
HelmiB

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

Related Questions