web-dev-qa-db-fra.com

Comment mettre en pause/mettre en sommeil un processus ou un processus sous Android?

Je veux faire une pause entre deux lignes de code, laissez-moi vous expliquer un peu: 

-> l'utilisateur clique sur un bouton (une carte en fait) et je le montre en changeant le fond de ce bouton: 

thisbutton.setBackgroundResource(R.drawable.icon);

-> après 1 seconde, je dois revenir à l'état précédent du bouton en modifiant l'arrière-plan: 

thisbutton.setBackgroundResource(R.drawable.defaultcard);

-> J'ai essayé de mettre en pause le fil entre ces deux lignes de code avec:

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

Cependant, cela ne fonctionne pas. Peut-être que c'est le processus et non le fil que je dois faire une pause?

J'ai aussi essayé (mais ça ne marche pas):

new Reminder(5);

Avec ça:

public class Reminder {

Timer timer;

        public Reminder(int seconds) {
            timer = new Timer();
            timer.schedule(new RemindTask(), seconds*1000);
        }

        class RemindTask extends TimerTask {
            public void run() {
                System.out.format("Time's up!%n");
                timer.cancel(); //Terminate the timer thread
            }
        }  
    }

Comment puis-je suspendre/dormir le fil ou le processus?

266
Hubert

Une solution à ce problème consiste à utiliser la méthode Handler.postDelayed () . Certains supports Google training suggèrent la même solution.

@Override
public void onClick(View v) {
    my_button.setBackgroundResource(R.drawable.icon);

    Handler handler = new Handler(); 
    handler.postDelayed(new Runnable() {
         @Override 
         public void run() { 
              my_button.setBackgroundResource(R.drawable.defaultcard); 
         } 
    }, 2000); 
}

Cependant, certains ont fait remarquer que la solution ci-dessus provoquait une fuite de mémoire , car elle utilisait une classe interne et anonyme non statique qui contient implicitement une référence à sa classe externe, l'activité. C'est un problème lorsque le contexte de l'activité est collecté. 

Une solution plus complexe qui évite les fuites de mémoire. Les sous-classes Handler et Runnable avec des classes internes statiques au sein de l'activité, car les classes internes statiques ne contiennent pas de référence implicite à leur classe externe:

private static class MyHandler extends Handler {}
private final MyHandler mHandler = new MyHandler();

public static class MyRunnable implements Runnable {
    private final WeakReference<Activity> mActivity;

    public MyRunnable(Activity activity) {
        mActivity = new WeakReference<>(activity);
    }

    @Override
    public void run() {
        Activity activity = mActivity.get();
        if (activity != null) {
            Button btn = (Button) activity.findViewById(R.id.button);
            btn.setBackgroundResource(R.drawable.defaultcard);
        }
    }
}

private MyRunnable mRunnable = new MyRunnable(this);

public void onClick(View view) {
    my_button.setBackgroundResource(R.drawable.icon);

    // Execute the Runnable in 2 seconds
    mHandler.postDelayed(mRunnable, 2000);
}

Notez que la Runnable utilise un WeakReference pour l'activité, ce qui est nécessaire dans une classe statique nécessitant un accès à l'interface utilisateur.

427
tronman

Vous pouvez essayer celui-ci il est short 

SystemClock.sleep(7000);

WARNING: Ne faites jamais cela sur un thread d'interface utilisateur.

Utilisez ceci pour dormir par exemple. fil de fond.


La solution complète à votre problème sera: Ceci est disponible API 1

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View button) {
                button.setBackgroundResource(R.drawable.avatar_dead);
                final long changeTime = 1000L;
                button.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        button.setBackgroundResource(R.drawable.avatar_small);
                    }
                }, changeTime);
            }
        });

Sans créer tmp Handler. De plus, cette solution est meilleure que @tronman car nous ne conservons pas la vue par Handler . Nous n’avons pas non plus de problème avec Handler créé à un mauvais thread;) 

Documentation

public vide statique sommeil (long ms)

Ajouté dans l'API niveau 1

Attend un nombre donné de millisecondes (de disponibilité), avant de revenir. Similaire à sleep (long), mais ne lève pas InterruptedException; Les événements interrupt () sont différés jusqu'au prochaine opération interruptible. Ne renvoie-t-il pas jusqu'à ce que le nombre de millisecondes spécifié se soit au moins écoulé?.

Paramètres

ms pour dormir avant de revenir, en millisecondes de disponibilité.

Code pour postDelayed from Afficher la classe:

/**
 * <p>Causes the Runnable to be added to the message queue, to be run
 * after the specified amount of time elapses.
 * The runnable will be run on the user interface thread.</p>
 *
 * @param action The Runnable that will be executed.
 * @param delayMillis The delay (in milliseconds) until the Runnable
 *        will be executed.
 *
 * @return true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the Runnable will be processed --
 *         if the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 *
 * @see #post
 * @see #removeCallbacks
 */
public boolean postDelayed(Runnable action, long delayMillis) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.postDelayed(action, delayMillis);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
    return true;
}
176
Dawid Drozd

J'utilise ceci:

Thread closeActivity = new Thread(new Runnable() {
  @Override
  public void run() {
    try {
      Thread.sleep(3000);
      // Do some stuff
    } catch (Exception e) {
      e.getLocalizedMessage();
    }
  }
});
24
Byt3

Vous ne voulez probablement pas le faire de cette façon. En plaçant une sleep() explicite dans votre gestionnaire d'événements sur lequel vous avez cliqué, vous verrouillez l'interface utilisateur entière pendant une seconde. Une alternative consiste à utiliser une sorte de simple coup Minuterie . Créez une TimerTask pour changer la couleur d'arrière-plan à la couleur par défaut et programmez-la sur le minuteur.

Une autre possibilité consiste à utiliser un Handler . Il y a un tutoriel à propos de quelqu'un qui a abandonné l'utilisation d'un minuteur pour utiliser un gestionnaire.

Incidemment, vous ne pouvez pas suspendre un processus. Un processus Java (ou Android) comporte au moins 1 thread et vous ne pouvez mettre en veille que les threads.

16
Daniel Yankowsky

J'utilise CountDownTime

new CountDownTimer(5000, 1000) {

    @Override
    public void onTick(long millisUntilFinished) {
        // do something after 1s
    }

    @Override
    public void onFinish() {
        // do something end times 5s
    }

}.start(); 
11
vudandroid

C’est ce que j’ai fait à la fin de la journée - cela fonctionne bien maintenant:

@Override
    public void onClick(View v) {
        my_button.setBackgroundResource(R.drawable.icon);
        // SLEEP 2 SECONDS HERE ...
        final Handler handler = new Handler(); 
        Timer t = new Timer(); 
        t.schedule(new TimerTask() { 
                public void run() { 
                        handler.post(new Runnable() { 
                                public void run() { 
                                 my_button.setBackgroundResource(R.drawable.defaultcard); 
                                } 
                        }); 
                } 
        }, 2000); 
    }
9
Hubert

En plus des réponses de M. Yankowsky, vous pouvez également utiliser postDelayed(). Ceci est disponible sur n’importe quel View (par exemple, votre carte) et prend un Runnable et une période de retard. Il exécute Runnable après ce délai.

8
CommonsWare

Ceci est mon exemple

Créer un utilitaire Java 

    import Android.app.ProgressDialog;
    import Android.content.Context;
    import Android.content.Intent;

    public class Utils {

        public static void showDummyWaitingDialog(final Context context, final Intent startingIntent) {
            // ...
            final ProgressDialog progressDialog = ProgressDialog.show(context, "Please wait...", "Loading data ...", true);

            new Thread() {
                public void run() {
                    try{
                        // Do some work here
                        sleep(5000);
                    } catch (Exception e) {
                    }
                    // start next intent
                    new Thread() {
                        public void run() {
                        // Dismiss the Dialog 
                        progressDialog.dismiss();
                        // start selected activity
                        if ( startingIntent != null) context.startActivity(startingIntent);
                        }
                    }.start();
                }
            }.start();  

        }

    }    
4
Stefano

Ou vous pouvez utiliser:

Android.os.SystemClock.sleep(checkEvery)

ce qui a l'avantage de ne pas nécessiter de wrapping try ... catch.

4
aaaa

Je sais que c'est un vieux fil, mais dans la documentation Android, j'ai trouvé une solution qui fonctionnait très bien pour moi ...

new CountDownTimer(30000, 1000) {

    public void onTick(long millisUntilFinished) {
        mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
    }

    public void onFinish() {
        mTextField.setText("done!");
    }
}.start();

https://developer.Android.com/reference/Android/os/CountDownTimer.html

J'espère que ça aide quelqu'un ...

0
John Byrne

Si vous utilisez Kotlin et coroutines , vous pouvez simplement faire

GlobalScope.launch {
   delay(3000) // In ms
   //Code after sleep
}

Et si vous avez besoin de mettre à jour l'interface utilisateur

GlobalScope.launch {
  delay(3000)
  GlobalScope.launch(Dispatchers.Main) {
    //Action on UI thread
  }
}
0
Guillaume