web-dev-qa-db-fra.com

Répéter une tâche avec un délai?

J'ai une variable dans mon code qui dit "statut".

Je souhaite afficher du texte dans l'application en fonction de cette valeur de variable. Cela doit être fait avec un délai spécifique.

C'est comme,

  • Vérifier la valeur de la variable d'état

  • Afficher du texte

  • Attendez 10 secondes

  • Vérifier la valeur de la variable d'état

  • Afficher du texte

  • Attendre 15 secondes

etc. Le délai peut varier et il est défini une fois le texte affiché.

J'ai essayé Thread.sleep(time delay) et cela a échoué. Un meilleur moyen de faire cela?

Vous devez utiliser la fonction Handler de postDelayed à cette fin. Il exécutera votre code avec le délai spécifié sur le thread principal de l'interface utilisateur afin que vous puissiez mettre à jour les contrôles de l'interface utilisateur.

private int mInterval = 5000; // 5 seconds by default, can be changed later
private Handler mHandler;

@Override
protected void onCreate(Bundle bundle) {

    // your code here

    mHandler = new Handler();
    startRepeatingTask();
}

@Override
public void onDestroy() {
    super.onDestroy();
    stopRepeatingTask();
}

Runnable mStatusChecker = new Runnable() {
    @Override 
    public void run() {
          try {
               updateStatus(); //this function can change value of mInterval.
          } finally {
               // 100% guarantee that this always happens, even if
               // your update method throws an exception
               mHandler.postDelayed(mStatusChecker, mInterval);
          }
    }
};

void startRepeatingTask() {
    mStatusChecker.run(); 
}

void stopRepeatingTask() {
    mHandler.removeCallbacks(mStatusChecker);
}
426
inazaruk

Pour les personnes intéressées, voici un cours que j'ai créé à l'aide du code d'inazaruk qui crée tout ce dont vous avez besoin (je l'ai appelé UIUpdater parce que je l'utilise pour mettre à jour périodiquement l'interface utilisateur, mais vous pouvez l'appeler comme bon vous semble):

import Android.os.Handler;
/**
 * A class used to perform periodical updates,
 * specified inside a runnable object. An update interval
 * may be specified (otherwise, the class will perform the 
 * update every 2 seconds).
 * 
 * @author Carlos Simões
 */
public class UIUpdater {
        // Create a Handler that uses the Main Looper to run in
        private Handler mHandler = new Handler(Looper.getMainLooper());

        private Runnable mStatusChecker;
        private int UPDATE_INTERVAL = 2000;

        /**
         * Creates an UIUpdater object, that can be used to
         * perform UIUpdates on a specified time interval.
         * 
         * @param uiUpdater A runnable containing the update routine.
         */
        public UIUpdater(final Runnable uiUpdater) {
            mStatusChecker = new Runnable() {
                @Override
                public void run() {
                    // Run the passed runnable
                    uiUpdater.run();
                    // Re-run it after the update interval
                    mHandler.postDelayed(this, UPDATE_INTERVAL);
                }
            };
        }

        /**
         * The same as the default constructor, but specifying the
         * intended update interval.
         * 
         * @param uiUpdater A runnable containing the update routine.
         * @param interval  The interval over which the routine
         *                  should run (milliseconds).
         */
        public UIUpdater(Runnable uiUpdater, int interval){
            UPDATE_INTERVAL = interval;
            this(uiUpdater);
        }

        /**
         * Starts the periodical update routine (mStatusChecker 
         * adds the callback to the handler).
         */
        public synchronized void startUpdates(){
            mStatusChecker.run();
        }

        /**
         * Stops the periodical update routine from running,
         * by removing the callback.
         */
        public synchronized void stopUpdates(){
            mHandler.removeCallbacks(mStatusChecker);
        }
}

Vous pouvez ensuite créer un objet UIUpdater dans votre classe et l'utiliser comme ceci:

...
mUIUpdater = new UIUpdater(new Runnable() {
         @Override 
         public void run() {
            // do stuff ...
         }
    });

// Start updates
mUIUpdater.startUpdates();

// Stop updates
mUIUpdater.stopUpdates();
...

Si vous souhaitez utiliser ceci en tant que programme de mise à jour d'activité, placez l'appel de démarrage dans la méthode onResume () et l'appel d'arrêt dans onPause (), afin que les mises à jour démarrent et s'arrêtent en fonction de la visibilité de l'activité.

32
ravemir

Je pense que le nouveau point chaud consiste à utiliser un ScheduledThreadPoolExecutor . Ainsi:

private final ScheduledThreadPoolExecutor executor_ = 
        new ScheduledThreadPoolExecutor(1);
this.executor_.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
    update();
    }
}, 0L, kPeriod, kTimeUnit);
22
Nels Beckman

La minuterie fonctionne bien. Ici, j'utilise Minuterie pour rechercher du texte après 1,5 secondes et mettre à jour l'interface utilisateur. J'espère que ça t'as aidé.

private Timer _timer = new Timer();

_timer.schedule(new TimerTask() {
    @Override
    public void run() {
        // use runOnUiThread(Runnable action)
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                search();
            }
        });
    }
}, timeInterval);
12
Kai Wang

La minuterie est une autre façon de faire votre travail, mais veillez à bien ajouter runOnUiThread si vous travaillez avec une interface utilisateur.

    import Java.text.SimpleDateFormat;
import Java.util.Calendar;
import Java.util.Timer;
import Java.util.TimerTask;

import Android.os.Bundle;
import Android.view.View;
import Android.view.View.OnClickListener;
import Android.widget.Button;
import Android.widget.CheckBox;
import Android.widget.TextView;
import Android.app.Activity;

public class MainActivity extends Activity {

 CheckBox optSingleShot;
 Button btnStart, btnCancel;
 TextView textCounter;

 Timer timer;
 MyTimerTask myTimerTask;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  optSingleShot = (CheckBox)findViewById(R.id.singleshot);
  btnStart = (Button)findViewById(R.id.start);
  btnCancel = (Button)findViewById(R.id.cancel);
  textCounter = (TextView)findViewById(R.id.counter);

  btnStart.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {

    if(timer != null){
     timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
     //singleshot delay 1000 ms
     timer.schedule(myTimerTask, 1000);
    }else{
     //delay 1000ms, repeat in 5000ms
     timer.schedule(myTimerTask, 1000, 5000);
    }
   }});

  btnCancel.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    if (timer!=null){
     timer.cancel();
     timer = null;
    }
   }
  });

 }

 class MyTimerTask extends TimerTask {

  @Override
  public void run() {
   Calendar calendar = Calendar.getInstance();
   SimpleDateFormat simpleDateFormat = 
     new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
   final String strDate = simpleDateFormat.format(calendar.getTime());

   runOnUiThread(new Runnable(){

    @Override
    public void run() {
     textCounter.setText(strDate);
    }});
  }

 }

}

et XML est ...

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:paddingBottom="@dimen/activity_vertical_margin"
Android:paddingLeft="@dimen/activity_horizontal_margin"
Android:paddingRight="@dimen/activity_horizontal_margin"
Android:paddingTop="@dimen/activity_vertical_margin"
Android:orientation="vertical"
tools:context=".MainActivity" >

<TextView
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:layout_gravity="center_horizontal"
    Android:autoLink="web"
    Android:text="http://Android-er.blogspot.com/"
    Android:textStyle="bold" />
<CheckBox 
    Android:id="@+id/singleshot"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:text="Single Shot"/>

Une autre façon d'utiliser CountDownTimer

new CountDownTimer(30000, 1000) {

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

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

Planifiez un compte à rebours jusqu'à une date ultérieure, avec des notifications régulières sur les intervalles. Exemple d'affichage d'un compte à rebours de 30 secondes dans un champ de texte:

pour les détails

5
Xar E Ahmer

Vous pouvez utiliser un gestionnaire pour publier du code exécutable. Cette technique est très bien décrite ici: https://guides.codepath.com/Android/Repeating-Periodic-Tasks

4
IgorGanapolsky

Dans mon cas, je devais exécuter un processus si l'une de ces conditions était vérifiée: si un processus précédent était terminé ou si 5 secondes s'étaient déjà écoulées. Alors, j'ai fait ce qui suit et j'ai plutôt bien travaillé:

private Runnable mStatusChecker;
private Handler mHandler;

class {
method() {
  mStatusChecker = new Runnable() {
            int times = 0;
            @Override
            public void run() {
                if (times < 5) {
                    if (process1.isRead()) {
                        executeProcess2();
                    } else {
                        times++;
                        mHandler.postDelayed(mStatusChecker, 1000);
                    }
                } else {
                    executeProcess2();
                }
            }
        };

        mHandler = new Handler();
        startRepeatingTask();
}

    void startRepeatingTask() {
       mStatusChecker.run();
    }

    void stopRepeatingTask() {
        mHandler.removeCallbacks(mStatusChecker);
    }


}

Si process1 est lu, il exécute process2. Sinon, les temps variables sont incrémentés et le gestionnaire est exécuté après une seconde. Il maintient une boucle jusqu'à ce que process1 soit lu ou que le temps soit égal à 5. Quand times est égal à 5, cela signifie que 5 secondes se sont écoulées et que, à chaque seconde, la clause if de process1.isRead () est exécutée.

4
jvdecamargo

Basé sur le post ci-dessus concernant le ScheduledThreadPoolExecutor , je suis arrivé avec un utilitaire qui répondait à mes besoins (je voulais déclencher une méthode toutes les 3 secondes):

class MyActivity {
    private ScheduledThreadPoolExecutor mDialogDaemon;

    private void initDebugButtons() {
        Button btnSpawnDialogs = (Button)findViewById(R.id.btn_spawn_dialogs);
        btnSpawnDialogs.setVisibility(View.VISIBLE);
        btnSpawnDialogs.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                spawnDialogs();
            }
        });
    }

    private void spawnDialogs() {
        if (mDialogDaemon != null) {
            mDialogDaemon.shutdown();
            mDialogDaemon = null;
        }
        mDialogDaemon = new ScheduledThreadPoolExecutor(1);
        // This process will execute immediately, then execute every 3 seconds.
        mDialogDaemon.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // Do something worthwhile
                    }
                });
            }
        }, 0L, 3000L, TimeUnit.MILLISECONDS);
    }
}
4
HelloImKevo

Faites-le à la manière d'Android avec l'aide de Gestionnaire .

Déclarez une classe handler interne qui ne perd pas de mémoire dans votre classe Activity/Fragment

/**
     * Instances of static inner classes do not hold an implicit
     * reference to their outer class.
     */
    private static class NonLeakyHandler extends Handler {
        private final WeakReference<FlashActivity> mActivity;

        public NonLeakyHandler(FlashActivity activity) {
            mActivity = new WeakReference<FlashActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            FlashActivity activity = mActivity.get();
            if (activity != null) {
                // ...
            }
        }
    }

Déclarez un runnable qui effectuera votre tâche répétitive dans votre classe d'activité/fragment

   private Runnable repeatativeTaskRunnable = new Runnable() {
        public void run() {
            new Handler(getMainLooper()).post(new Runnable() {
                @Override
                public void run() {

         //DO YOUR THINGS
        }
    };

Initialiser l'objet Handler dans votre activité/fragment (ici FlashActivity est ma classe d'activité)

//Task Handler
private Handler taskHandler = new NonLeakyHandler(FlashActivity.this);

Pour répéter une tâche après un intervalle de temps fixe

taskHandler.postDelayed (repeatativeTaskRunnable, DELAY_MILLIS);

Pour arrêter la répétition de la tâche

taskHandler .removeCallbacks (repeatativeTaskRunnable);

MISE À JOUR: À Kotlin:

    //update interval for widget
    override val UPDATE_INTERVAL = 1000L

    //Handler to repeat update
    private val updateWidgetHandler = Handler()

    //runnable to update widget
    private var updateWidgetRunnable: Runnable = Runnable {
        run {
            //Update UI
            updateWidget()
            // Re-run it after the update interval
            updateWidgetHandler.postDelayed(updateWidgetRunnable, UPDATE_INTERVAL)
        }

    }

 // SATART updating in foreground
 override fun onResume() {
        super.onResume()
        updateWidgetHandler.postDelayed(updateWidgetRunnable, UPDATE_INTERVAL)
    }


    // REMOVE callback if app in background
    override fun onPause() {
        super.onPause()
        updateWidgetHandler.removeCallbacks(updateWidgetRunnable);
    }
4
Hitesh Sahu

Essayez de suivre l'exemple cela fonctionne !!!

Utilisez [Handler] dans la méthode onCreate () qui utilise la méthode postDelayed () qui provoque l'ajout de Runnable à la file d'attente de messages et s'exécute au bout du délai spécifié, égal à 0, dans l'exemple donné. 1

Référez-vous ce code:



public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
    //------------------
    //------------------
    Android.os.Handler customHandler = new Android.os.Handler();
            customHandler.postDelayed(updateTimerThread, 0);
}

private Runnable updateTimerThread = new Runnable()
{
        public void run()
        {
            //write here whaterver you want to repeat
            customHandler.postDelayed(this, 1000);
        }
};
 </ code>

4
Gazal Patel

Pour les personnes utilisant Kotlin, réponse d’inazaruk ne fonctionnera pas, le IDE nécessitera l’initialisation de la variable. Ainsi, au lieu d’utiliser le postDelayed à l’intérieur du Runnable, nous allons l'utiliser dans une méthode séparée.

  • Initialisez votre Runnable comme ceci:

    private var myRunnable = Runnable {
        //Do some work
        //Magic happens here ↓
        runDelayedHandler(1000)   }
    
  • Initialisez votre méthode runDelayedHandler comme ceci:

     private fun runDelayedHandler(timeToWait : Long) {
        if (!keepRunning) {
            //Stop your handler
            handler.removeCallbacksAndMessages(null)
            //Do something here, this acts like onHandlerStop
        }
        else {
            //Keep it running
            handler.postDelayed(myRunnable, timeToWait)
        }
    }
    
  • Comme vous pouvez le constater, cette approche vous permettra de contrôler la durée de la tâche. Garder une trace de keepRunning et la modifier au cours de la durée de vie de l'application fera le travail à votre place.

0
Tamim Attafi