Je veux pouvoir appeler la méthode suivante après un délai spécifié . Dans l’objectif C, il y avait quelque chose comme:
[self performSelector:@selector(DoSomething) withObject:nil afterDelay:5];
Existe-t-il un équivalent de cette méthode dans Android avec Java? Par exemple, je dois pouvoir appeler une méthode après 5 secondes.
public void DoSomething()
{
//do something here
}
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);
Je ne pouvais utiliser aucune des autres réponses dans mon cas… .. J'ai plutôt utilisé le minuteur Java natif.
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// this code will be executed after 2 seconds
}
}, 2000);
Remarque: Cette réponse a été donnée lorsque la question ne spécifiait pas Android comme contexte. Pour une réponse spécifique au fil de l'interface utilisateur Android regardez ici.
Il semble que l'API Mac OS laisse le thread actuel continuer et planifie l'exécution de la tâche de manière asynchrone. En Java, la fonction équivalente est fournie par le paquetage Java.util.concurrent
. Je ne suis pas sûr des limitations qu'Android pourrait imposer.
private static final ScheduledExecutorService worker =
Executors.newSingleThreadScheduledExecutor();
void someMethod() {
⋮
Runnable task = new Runnable() {
public void run() {
/* Do something… */
}
};
worker.schedule(task, 5, TimeUnit.SECONDS);
⋮
}
Pour exécuter quelque chose dans le thread de l'interface utilisateur après 5 secondes:
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
//Do something here
}
}, 5000);
vous pouvez utiliser Handler dans 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);
}
});
Merci pour toutes les bonnes réponses, j'ai trouvé la solution qui convient le mieux à mes besoins.
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
}
}
Voir cette démo:
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?");
}
}
Si vous devez utiliser le gestionnaire, mais que vous êtes dans un autre thread, vous pouvez utiliser runonuithread
pour exécuter le gestionnaire dans le thread de l'interface utilisateur. Cela vous épargnera des exceptions levées demandant d’appeler Looper.Prepare()
runOnUiThread(new Runnable() {
@Override
public void run() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 1 second
}
}, 1000);
}
});
On dirait que c'est plutôt brouillon, mais c'est l'un des moyens.
Je préfère utiliser la méthode View.postDelayed()
, code simple ci-dessous:
mView.postDelayed(new Runnable() {
@Override
public void run() {
// Do something after 1000 ms
}
}, 1000);
Voici ma solution la plus courte:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
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);
Si vous utilisez Android Studio 3.0 et versions ultérieures, vous pouvez utiliser les expressions lambda. La méthode callMyMethod()
est appelée après 2 secondes:
new Handler().postDelayed(() -> callMyMethod(), 2000);
Si vous devez annuler l’exécution différée, utilisez ceci:
Handler handler = new Handler();
handler.postDelayed(() -> callMyMethod(), 2000);
// When you need to cancel all your posted runnables just use:
handler.removeCallbacksAndMessages(null);
Je suggère le Timer , il vous permet de programmer l’appel d’une méthode sur un intervalle très spécifique. Cela ne bloquera pas votre interface utilisateur et maintiendra la réactivité de votre application pendant l'exécution de la méthode.
L'autre option est le wait (); , cela bloquera le thread en cours pour la durée spécifiée. Votre interface utilisateur cessera alors de répondre si vous le faites sur le fil de l'interface utilisateur.
Kotlin
&Java
Plusieurs façons
Handler
Handler().postDelayed({
TODO("Do something")
}, 2000)
Timer().schedule(object : TimerTask() {
override fun run() {
TODO("Do something")
}
}, 2000)
Ou même plus court
Timer().schedule(timerTask {
TODO("Do something")
}, 2000)
Ou le plus court serait
Timer().schedule(2000) {
TODO("Do something")
}
Executors
Executors.newSingleThreadScheduledExecutor().schedule({
TODO("Do something")
}, 2, TimeUnit.SECONDS)
En 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);
Vous pouvez l'utiliser pour la solution la plus simple:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Write your code here
}
}, 5000); //Timer is in ms here.
Sinon, ci-dessous peut être une autre solution utile propre:
new Handler().postDelayed(() ->
{/*Do something here*/},
5000); //time in ms
Vous pouvez le rendre beaucoup plus propre en utilisant les expressions lambda nouvellement introduites:
new Handler().postDelayed(() -> {/*your code here*/}, time);
J'ai créé une méthode plus simple pour appeler cela.
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);
}
Pour l'utiliser, il suffit d'appeler: .CallWithDelay(5000, this, "DoSomething");
Donc, il y a quelques choses à considérer ici car il y a tellement de façons de peauner ce chat. Bien que toutes les réponses aient déjà été données, sélectionnées et choisies. Je pense qu'il est important que cela soit revisité avec des directives de codage appropriées pour éviter que quiconque ne prenne la mauvaise direction simplement à cause de "la réponse simple sélectionnée par la majorité".
Commençons donc par discuter de la réponse simple post-différée qui est la réponse sélectionnée par le gagnant dans l’ensemble de ce fil de discussion.
Quelques points à considérer. Après le délai postérieur, vous pouvez rencontrer des fuites de mémoire, des objets morts, des cycles de vie qui ont disparu et bien plus encore. Il est donc important de le gérer correctement. Vous pouvez le faire de plusieurs manières.
Par souci de développement moderne, je fournirai en KOTLIN
Voici un exemple simple d'utilisation du thread d'interface utilisateur sur un rappel et confirmant que votre activité est toujours active lorsque vous appuyez sur le rappel.
Handler(Looper.getMainLooper()).postDelayed({
if(activity != null && activity?.isFinishing == false){
txtNewInfo.visibility = View.GONE
}
}, NEW_INFO_SHOW_TIMEOUT_MS)
Toutefois, cela n’est pas encore parfait, car il n’ya aucune raison de faire appel à votre rappel si l’activité a disparu. il serait donc préférable de conserver une référence et de supprimer les rappels comme celui-ci.
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)
}
}
et bien sûr gérer le nettoyage sur le onPause afin qu'il ne frappe pas le rappel.
override fun onPause() {
super.onPause()
mHandler.removeCallbacks(null)
}
Maintenant que nous avons discuté de l'évidence, parlons d'une option plus propre avec les coroutines et le kotlin des temps modernes :). Si vous ne les utilisez pas encore, vous manquez vraiment.
fun doActionAfterDelay()
launch(UI) {
delay(MS_TO_DELAY)
actionToTake()
}
}
ou si vous voulez toujours lancer une interface utilisateur sur cette méthode, vous pouvez simplement faire:
fun doActionAfterDelay() = launch(UI){
delay(MS_TO_DELAY)
actionToTake()
}
Bien sûr, tout comme le PostDelayed, vous devez vous assurer que vous gérez l'annulation afin de pouvoir effectuer les vérifications d'activité après l'appel différé ou de l'annuler dans onPause, tout comme pour l'autre 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}")
}
}
}
}
// gérer le nettoyage
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
}
}
Si vous insérez le lancement (UI) dans la signature de la méthode, le travail peut être affecté dans la ligne de code appelante.
la morale de l’histoire est donc d’être en sécurité avec vos actions différées, d’enlever vos rappels ou d’annuler vos tâches et bien sûr de confirmer que vous avez le bon cycle de vie pour toucher les éléments de votre rappel différé. Les Coroutines proposent également des actions annulables.
Il convient également de noter que vous devez généralement gérer les diverses exceptions pouvant découler des coroutines. Par exemple, une annulation, une exception, un délai d'attente, quoi que vous décidiez d'utiliser. Voici un exemple plus avancé si vous décidez de commencer réellement à utiliser des 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}")
}
}
Au-dessous on travaille quand vous obtenez,
Java.lang.RuntimeException: Impossible de créer un gestionnaire dans un thread qui n'a pas appelé Looper.prepare ()
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
C'est très facile avec la CountDownTimer
. Pour plus de détails 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();
Voici un autre moyen délicat: il ne lève pas d'exception lorsque les éléments exécutables de l'interface utilisateur changent.
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) {
}
}
Vous pouvez appeler l'animation comme ceci:
view.startAnimation(new SimpleDelayAnimation(delayRunnable, 500));
L'animation peut être attachée à n'importe quelle vue.
tout le monde semble oublier de nettoyer le gestionnaire avant de poster un nouveau message ou message exécutable dessus Sinon, ils pourraient potentiellement s'accumuler et provoquer un mauvais comportement.
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.
J'aime les choses plus propres: Voici mon implémentation, le code en ligne à utiliser dans votre méthode
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
Voici la réponse à Kotlin vous paresseux, paresseux:
Handler().postDelayed({
//doSomethingHere()
}, 1000)
En utilisant Kotlin, nous pouvons obtenir les résultats suivants:
Handler().postDelayed({
// do something after 1000ms
}, 1000)
Sous Android, nous pouvons écrire ci-dessous le code kotlin pour retarder l'exécution de toute fonction
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()
}
}
Une solution adaptée sous 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
}
}
Si vous utilisez RxAndroid, la gestion des threads et des erreurs devient beaucoup plus facile. Le code suivant s'exécute après un délai
Observable.timer(delay, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aLong -> {
// Execute code here
}, Throwable::printStackTrace);
Il y a beaucoup de façons de faire cela, mais le mieux est d'utiliser handler comme ci-dessous
long millisecDelay=3000
Handler().postDelayed({
// do your work here
},millisecDelay)
Solution similaire mais beaucoup plus propre à utiliser
Écrire cette fonction en dehors de la classe
fun delay(duration: Long, `do`: () -> Unit) {
Handler().postDelayed(`do`, duration)
}
Usage:
delay(5000) {
//Do your work here
}
Pour un délai post-traitement de ligne simple, vous pouvez procéder comme suit:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// Do someting
}
}, 3000);
J'espère que ça aide