Как вызвать метод после задержки в Android

Я хочу иметь возможность вызвать следующий метод после указанной задержки.  В объективе c было что-то вроде:

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

Есть ли эквивалент этого метода в android с java? Например, мне нужно иметь возможность вызывать метод через 5 секунд.

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

Ответ 1

Котлин

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


Ответ 2

Я не мог использовать какие-либо другие ответы в моем случае. Вместо этого я использовал собственный таймер Java.

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

Ответ 3

Примечание. Этот ответ был дан, когда вопрос не указывал на Android как контекст. Для ответа, характерного для потока пользовательского интерфейса Android смотрите здесь.


Похоже, что 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);
  ⋮
}

Ответ 4

За выполнение чего-то в потоке пользовательского интерфейса через 5 секунд:

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

Ответ 5

вы можете использовать Handler внутри UIThread:

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

    }
});

Ответ 6

Спасибо за все замечательные ответы, я нашел решение, которое наилучшим образом соответствует моим потребностям.

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

Ответ 7

Если вам нужно использовать Handler, но вы используете другой поток, вы можете использовать runonuithread для запуска обработчика в потоке пользовательского интерфейса. Это избавит вас от Исключений, запрошенных на вызов 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

Смотрите это демо:

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

Ответ 9

Я предпочитаю использовать View.postDelayed(), простой код ниже:

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

Ответ 10

Вот мое кратчайшее решение:

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

Ответ 11

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

Ответ 12

Если вы используете Android Studio 3.0 и выше, вы можете использовать лямбда-выражения. Метод 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);

Ответ 13

Я предлагаю Timer, он позволяет планировать метод, который будет вызываться на очень конкретном интервале. Это не будет блокировать ваш пользовательский интерфейс и не будет поддерживать ваше приложение во время выполнения метода.

Другим вариантом является метод wait();, который блокирует текущий поток в течение указанного периода времени. Это приведет к тому, что ваш пользовательский интерфейс перестанет отвечать, если вы делаете это в потоке пользовательского интерфейса.

Ответ 14

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)

На яве

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

Вы можете использовать это для Simplest Solution:

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

Else, Ниже может быть еще одно полезное решение:

new Handler().postDelayed(() -> 
{/*Do something here*/}, 
5000); //time in ms

Ответ 16

Вы можете сделать его более чистым, используя недавно введенные лямбда-выражения:

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

Ответ 17

Я создал более простой метод для вызова этого.

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

Ниже один работает, когда вы получаете,

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

Это очень просто, используя 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();

Ответ 20

Поэтому есть несколько вещей, которые следует учитывать здесь, поскольку существует так много способов скинуть этот кот. Хотя ответы уже были выбраны и выбраны. Я думаю, что важно, чтобы это пересматривалось с правильными инструкциями по кодированию, чтобы избежать того, чтобы кто-то шел в неправильном направлении только из-за "большинства выбранных простых ответов".

Поэтому сначала давайте обсудим простой ответ "Отложенная почта", который является победителем, выбранным в целом в этом потоке.

Несколько вещей, чтобы рассмотреть. После задержки сообщения вы можете столкнуться с утечками памяти, мертвыми объектами, оставшимися жизненными циклами и т.д. Поэтому правильное обращение с ним также важно. Вы можете сделать это несколькими способами.

Ради современного развития, я поставлю в КОТЛИН

Вот простой пример использования потока пользовательского интерфейса для обратного вызова и подтверждения того, что ваша активность все еще жива и работоспособна, когда вы нажимаете обратный вызов.

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

Теперь, когда мы поговорили через очевидное, расскажите о более чистом варианте с современными деньгами и котлин :). Если вы еще не используете их, вы действительно упускаете.

   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) в подпись метода, задание может быть назначено в вызывающей строке кода.

так что мораль этой истории должна быть безопасной с вашими отложенными действиями, убедитесь, что вы удалили свои обратные вызовы или отменили свои задания, и, конечно же, подтвердите, что у вас есть правильный жизненный цикл, чтобы коснуться предметов в вашем обратном вызове задержки. 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}")
            }
        }

Ответ 21

Для простой строки Handle Post delay вы можете сделать следующее:

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

надеюсь, это поможет

Ответ 22

Вот еще один сложный способ: он не будет генерировать исключение, когда элементы пользовательского интерфейса с изменяемым изменением.

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

Анимация может быть прикреплена к любому виду.

Ответ 23

все, похоже, забывают очистить обработчик, прежде чем публиковать на нем новую версию или сообщение. В противном случае они могут потенциально накапливаться и вызывать плохое поведение.

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.

Ответ 24

Вот ответ в Котлин вам ленивые, ленивые люди:

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

Ответ 25

Я люблю вещи чище: вот моя реализация, встроенный код для использования внутри вашего метода

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

Ответ 26

Подходящее решение в 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

Если вы используете RxAndroid, то обработка потоков и ошибок станет намного проще. Следующий код выполняется с задержкой

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

Ответ 28

Аналогичное решение, но гораздо более чистое в использовании

Напишите эту функцию вне класса

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

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

}

Использование:

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

Ответ 29

В 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

Есть много способов сделать это, но лучше всего использовать обработчик, как показано ниже

long millisecDelay=3000

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