it-swarm.com.ru

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

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

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

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

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

Лучшая версия - Котлин:

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


Лучшая версия - Java:

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


1599
kontinuity

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

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

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


Похоже, что API Mac OS позволяет текущему потоку продолжить и планирует выполнение задачи асинхронно. В 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);
  ⋮
}
180
erickson

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

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

вы можете использовать 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);

    }
});
38
Hossam Ghareeb

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

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

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

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

Если вам нужно использовать обработчик, но вы находитесь в другом потоке, вы можете использовать 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);
    }
});

Выглядит довольно грязно, но это один из способов.

21
noob

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

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

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

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        //Do something after 100ms
    }
}, 100);
13
Alecs
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); 
10
Vishnu

Если вы используете 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);
7
vovahost

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

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

6
Nate

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

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

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
5
Crime_Master_GoGo

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

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

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

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

3
HelmiB

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

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

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

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

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

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

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

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);
2
Sazzad Hissain Khan

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

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

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

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

1
cdytoby

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

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.
1
Dan Alboteanu

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

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

вот ответ в Kotlin вы ленивые, ленивые люди:

Handler().postDelayed({
//doSomethingHere()
}, 1000)
1
Daniel Wilson

В 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()
}
}
0
Ahasan

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

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

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

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

long millisecDelay=3000

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

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

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

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

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

}

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

delay(5000) {
    //Do your work here
}
0
Manohar Reddy

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

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

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

0
MrG