web-dev-qa-db-fra.com

Comment appeler une méthode après un délai sous Android

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

Meilleure version - Kotlin:

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


Meilleure version - Java:

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


1599
kontinuity

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);
281
Jules Colle

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);
  ⋮
}
180
erickson

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

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

    }
});
38
Hossam Ghareeb

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

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

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.

21
noob

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

Voici ma solution la plus courte: 

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

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

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.

6
Nate

Kotlin & Java Plusieurs façons

1. Utilisation de Handler

Handler().postDelayed({
    TODO("Do something")
    }, 2000)

2. Utilisation de la minuterie

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

3. Utilisation de Executors

Executors.newSingleThreadScheduledExecutor().schedule({
    TODO("Do something")
}, 2, TimeUnit.SECONDS)

En java

1. Utilisation de Handler

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

2. Utilisation de Timer

new Timer().schedule(new TimerTask() {          
    @Override
    public void run() {
        // Do something
    }
}, 2000);

3. Utilisation de 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

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

Vous pouvez le rendre beaucoup plus propre en utilisant les expressions lambda nouvellement introduites:

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

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

3
HelmiB

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

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

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();
2
Abdul Rizwan

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.

1
cdytoby

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

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

Voici la réponse à Kotlin vous paresseux, paresseux:

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

En utilisant Kotlin, nous pouvons obtenir les résultats suivants:

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

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

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

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

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)
0
Shivam Yadav

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
}
0
Manohar Reddy

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

0
MrG