Как вызвать метод после задержки в Android - PullRequest
681 голосов
/ 18 июня 2010

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

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

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

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

Ответы [ 31 ]

10 голосов
/ 09 июня 2012
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); 
8 голосов
/ 20 сентября 2017

Если вы используете 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);
8 голосов
/ 27 ноября 2018

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);
6 голосов
/ 18 июня 2010

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

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

5 голосов
/ 29 января 2018

Вы можете использовать это для простейшего решения:

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
4 голосов
/ 21 июня 2017

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

new Handler().postDelayed(() -> {/*your code here*/}, time);
3 голосов
/ 08 ноября 2018

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

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);
3 голосов
/ 16 марта 2016

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

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

2 голосов
/ 19 февраля 2019

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

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

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

2 голосов
/ 25 сентября 2018

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

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

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

Ради современной разработки я приведу в KOTLIN

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

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

или если вы хотите всегда запускать пользовательский интерфейс для этого метода, вы можете просто сделать:

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