Come impostare un timer in Android


Risposte:


143

Modo Java standard per utilizzare i timer tramite java.util.Timer e java.util.TimerTask funziona bene in Android, ma è necessario tenere presente che questo metodo crea un nuovo thread.

Puoi prendere in considerazione l'utilizzo della classe Handler (android.os.Handler) molto conveniente e inviare messaggi al gestore tramite sendMessageAtTime(android.os.Message, long)o sendMessageDelayed(android.os.Message, long). Una volta ricevuto un messaggio, è possibile eseguire le attività desiderate. La seconda opzione sarebbe quella di creare un oggetto Runnable e programmarlo tramite le funzioni di Handler postAtTime(java.lang.Runnable, long)o postDelayed(java.lang.Runnable, long).


10
Questo è il modo sbagliato di fare le cose in Android. In Android, vuoi utilizzare Alarm Manager (developer.android.com/reference/android/app/AlarmManager.html) per eseguire attività in futuro.
Kurtis Nusbaum,

9
@Kurtis Nusbaum La domanda non dice quanto lontano sia il compito in futuro.
Christopher Perry,

67
@KurtisNusbaum Questo non è necessariamente vero, dipende dal contesto. I documenti su AlarmManager dicono: "Nota: Alarm Manager è destinato ai casi in cui si desidera eseguire il codice dell'applicazione in un momento specifico, anche se l'applicazione non è attualmente in esecuzione. Per le normali operazioni di temporizzazione (tick, timeout, ecc.) è più facile e molto più efficiente usare Handler ".
Christopher Perry,

5
@Scienceprodigy Ah, capisco. Giusto.
Kurtis Nusbaum,

10
l'utilizzo del metodo Handler per programmare un'attività è affidabile solo se l'applicazione ha acquisito un wakeLock e quindi si è certi che il telefono non debba passare allo stato di sospensione. Se il telefono passa allo stato di sospensione, sendMessageDelayed e sendMessageAtTime non funzioneranno. Quindi, in quello scenario, AlarmManager sarebbe una scelta affidabile.
crazyaboutliv,

159

sì, il timer di Java può essere utilizzato , ma poiché la domanda richiede un modo migliore (per dispositivi mobili). Che è spiegato qui .


Per il bene di StackOverflow:

Poiché Timer crea un nuovo thread, può essere considerato pesante,

se tutto ciò che serve è ricevere una richiamata mentre l'attività è in esecuzione, è possibile utilizzare un gestore insieme a

Eseguibile :

private final int interval = 1000; // 1 Second
private Handler handler = new Handler();
private Runnable runnable = new Runnable(){
    public void run() {
        Toast.makeText(MyActivity.this, "C'Mom no hands!", Toast.LENGTH_SHORT).show();
    }
};
...
handler.postAtTime(runnable, System.currentTimeMillis()+interval);
handler.postDelayed(runnable, interval);

o un messaggio

private final int EVENT1 = 1; 
private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {         
        case Event1:
            Toast.makeText(MyActivity.this, "Event 1", Toast.LENGTH_SHORT).show();
            break;

        default:
            Toast.makeText(MyActivity.this, "Unhandled", Toast.LENGTH_SHORT).show();
            break;
        }
    }
};

...

Message msg = handler.obtainMessage(EVENT1);
handler.sendMessageAtTime(msg, System.currentTimeMillis()+interval);
handler.sendMessageDelayed(msg, interval);

su una nota a margine questo approccio può essere utilizzato, se si desidera eseguire un pezzo di codice nel thread dell'interfaccia utente da un altro thread.

se è necessario ricevere una chiamata anche se l'attività non è in esecuzione, è possibile utilizzare un AlarmManager


1
Oh sì, ho cercato su Google esattamente questa risposta. Prendi il mio voto per il link utile.
Ulidtko,

1
aggiornato il collegamento, parla di google che ha problemi a mantenere i collegamenti.
Samuel,

1
Questo articolo del 2007 - senza dire che è sbagliato, ma sono sempre sospettoso di un articolo mobile se ha più di 3 anni. Le cose cambiano abbastanza rapidamente.
StackOverflow del

1
sarebbe più simile a StackOverflow se potessi citare i punti principali del tuo link qui nella tua risposta.
n611x007

1
@naxa, i miei due centesimi per rendere questa risposta più simile a StackOverflow.
Samuel,

131

Come ho visto, java.util.Timer è il più utilizzato per implementare un timer.

Per un'attività ripetuta:

new Timer().scheduleAtFixedRate(task, after, interval);

Per una singola esecuzione di un'attività:

new Timer().schedule(task, after);


attività essendo il metodo da eseguire
dopo il tempo di esecuzione iniziale
( intervallo il tempo per ripetere l'esecuzione)


9
Aggiungo solo che il tempo è in millisecondi
Uri il

2
documenti dev Android per scheduleAtFixedRate
n611x007

1
taskpuò essere un'istanza della tua classe che eredita da java.util.TimerTask e sostituisce void run().
n611x007

2
Così tanti voti. Puoi farlo. Ma @Samuel descrive il modo migliore. Vedi il suo link "Che è spiegato qui" per il motivo. Inoltre, non è possibile aggiornare l'interfaccia utente da un thread Timer! E vedere queste altre risposte Handler basati in altri thread: (semplici) stackoverflow.com/a/6702767/199364 , o (spettacoli vari alternative) stackoverflow.com/a/4598737/199364
ToolmakerSteve

@quemeful perché non si tratta sempre di convenienza, si tratta di qualità ed efficienza del codice. Questo modo di fare utilizza più risorse rispetto all'utilizzo di Handler
Depth

33

Spero che questo sia utile e possa richiedere meno sforzi per implementare la classe CountDownTimer di Android

per esempio

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

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

1
Questo è più semplice e colpisce proprio sulla testa per un semplice conto alla rovescia come l'inizio di una riproduzione video
Vijay Kumar Kanta

17

Probabilmente Timerconcept

new CountDownTimer(40000, 1000) { //40000 milli seconds is total time, 1000 milli seconds is time interval

 public void onTick(long millisUntilFinished) {
  }
  public void onFinish() {
 }
}.start();

o

Metodo 2 ::

Programmare il timer

Aggiungi una nuova variabile di int denominata time. Impostalo su 0. Aggiungi il seguente codice alla funzione onCreate in MainActivity.java.

//Declare the timer
Timer t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {

    @Override
    public void run() {
        //Called each time when 1000 milliseconds (1 second) (the period parameter)
    }

},
//Set how long before to start calling the TimerTask (in milliseconds)
0,
//Set the amount of time between each execution (in milliseconds)
1000);

Vai al metodo di esecuzione e aggiungi il seguente codice.

//We must use this function in order to change the text view text
runOnUiThread(new Runnable() {

    @Override
    public void run() {
        TextView tv = (TextView) findViewById(R.id.main_timer_text);
        tv.setText(String.valueOf(time));
        time += 1;
    }

});

11

È situazionale.

La documentazione di Android suggerisce che è necessario utilizzare AlarmManager per registrare un Intento che verrà attivato all'ora specificata se l'applicazione potrebbe non essere in esecuzione.

Altrimenti, dovresti usare Handler.

Nota: Alarm Manager è destinato ai casi in cui si desidera eseguire il codice dell'applicazione in un momento specifico, anche se l'applicazione non è attualmente in esecuzione. Per le normali operazioni di cronometraggio (tick, timeout, ecc.) È più facile e molto più efficiente usare Handler.


11

Eccoci .. Avremo bisogno di due lezioni. Sto pubblicando un codice che cambia il profilo audio mobile dopo ogni 5 secondi (5000 mili secondi) ...

La nostra prima classe

public class ChangeProfileActivityMain extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        Timer timer = new Timer();
        TimerTask updateProfile = new CustomTimerTask(ChangeProfileActivityMain.this);
        timer.scheduleAtFixedRate(updateProfile, 0, 5000);
    }

}

La nostra seconda classe

public class CustomTimerTask extends TimerTask {

    private AudioManager audioManager;
    private Context context;
    private Handler mHandler = new Handler();

    // Write Custom Constructor to pass Context
    public CustomTimerTask(Context con) {
        this.context = con;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        // your code starts here.
        // I have used Thread and Handler as we can not show Toast without starting new thread when we are inside a thread.
        // As TimePicker has run() thread running., So We must show Toast through Handler.post in a new Thread. Thats how it works in Android..
        new Thread(new Runnable() {
            @Override
            public void run() {
                audioManager = (AudioManager) context.getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
                            audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
                            Toast.makeText(context, "Ringer Mode set to Normal", Toast.LENGTH_SHORT).show();
                        } else {
                            audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
                            Toast.makeText(context, "Ringer Mode set to Silent", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            }
        }).start();

    }

}

5

Sono un principiante Android, ma ecco la classe timer che ho creato in base alle risposte sopra. Funziona con la mia app ma accolgo con favore eventuali suggerimenti.

Esempio di utilizzo:

...{
public Handler uiHandler = new Handler();

  private Runnable runMethod = new Runnable()
    {
        public void run()
        {
              // do something
        }
    };

    timer = new UITimer(handler, runMethod, timeoutSeconds*1000);       
        timer.start();
}...

public class UITimer
{
    private Handler handler;
    private Runnable runMethod;
    private int intervalMs;
    private boolean enabled = false;
    private boolean oneTime = false;

    public UITimer(Handler handler, Runnable runMethod, int intervalMs)
    {
        this.handler = handler;
        this.runMethod = runMethod;
        this.intervalMs = intervalMs;
    }

    public UITimer(Handler handler, Runnable runMethod, int intervalMs, boolean oneTime)
    {
        this(handler, runMethod, intervalMs);
        this.oneTime = oneTime;
    }

    public void start()
    {
        if (enabled)
            return;

        if (intervalMs < 1)
        {
            Log.e("timer start", "Invalid interval:" + intervalMs);
            return;
        }

        enabled = true;
        handler.postDelayed(timer_tick, intervalMs);        
    }

    public void stop()
    {
        if (!enabled)
            return;

        enabled = false;
        handler.removeCallbacks(runMethod);
        handler.removeCallbacks(timer_tick);
    }

    public boolean isEnabled()
    {
        return enabled;
    }

    private Runnable timer_tick = new Runnable()
    {
        public void run()
        {
            if (!enabled)
                return;

            handler.post(runMethod);

            if (oneTime)
            {
                enabled = false;
                return;
            }

            handler.postDelayed(timer_tick, intervalMs);
        }
    }; 
}

3

Sto usando un gestore e eseguibile per creare un timer. Lo avvolgo in una classe astratta. Derivalo / implementalo e sei a posto:

 public static abstract class SimpleTimer {
    abstract void onTimer();

    private Runnable runnableCode = null;
    private Handler handler = new Handler();

    void startDelayed(final int intervalMS, int delayMS) {
        runnableCode = new Runnable() {
            @Override
            public void run() {
                handler.postDelayed(runnableCode, intervalMS);
                onTimer();
            }
        };
        handler.postDelayed(runnableCode, delayMS);
    }

    void start(final int intervalMS) {
        startDelayed(intervalMS, 0);
    }

    void stop() {
        handler.removeCallbacks(runnableCode);
    }
}

Si noti che handler.postDelayedviene chiamato prima del codice da eseguire - questo renderà il timer più chiuso come "previsto". Tuttavia, nei casi in cui il timer viene eseguito di frequente e l'attività ( onTimer()) è lunga - potrebbero esserci sovrapposizioni. Se si desidera iniziare il conteggio al intervalMStermine dell'attività, spostare la onTimer()chiamata sopra una linea.


2

Credo che il modo per farlo su Android sia che hai bisogno di un servizio in background per essere in esecuzione. In quell'applicazione in background, crea il timer. Quando il timer "spunta" (imposta l'intervallo per quanto tempo vuoi aspettare), avvia la tua attività che vuoi iniziare.

http://developer.android.com/guide/topics/fundamentals.html (<- questo articolo spiega la relazione tra attività, servizi, intenti e altri fondamenti fondamentali dello sviluppo Android)


1

Prima usavo ( Timer, TimerTask) oltre Handlera dare il via periodicamente ad attività (che richiedevano tempo). Ora ho passato il tutto a RxJava. RxJava fornisce ciò Observable.timerche è più semplice, meno soggetto a errori, senza problemi da usare.

public class BetterTimerFragment extends Fragment {
  public static final String TAG = "BetterTimer";
  private TextView timeView;
  private Subscription timerSubscription;

  @Override
  public View onCreateView(LayoutInflater inflater,
                           @Nullable ViewGroup container,
                           @Nullable Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_timer, container, false);
  }

  @Override
  public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    timeView = (TextView) view.findViewById(R.id.timeView);
  }

  @Override
  public void onResume() {
    super.onResume();

    // Right after the app is visible to users, delay 2 seconds
    // then kick off a (heavy) task every 10 seconds.
    timerSubscription = Observable.timer(2, 10, TimeUnit.SECONDS)
        .map(new Func1<Long, String>() {
          @Override
          public String call(Long unused) {
            // TODO: Probably do time-consuming work here.
            // This runs on a different thread than the main thread.
            return "Time: " + System.currentTimeMillis();
          }
        })
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<String>() {
          @Override
          public void call(String timeText) {
            // The result will then be propagated back to the main thread.
            timeView.setText(timeText);
          }
        }, new Action1<Throwable>() {
          @Override
          public void call(Throwable throwable) {
            Log.e(TAG, throwable.getMessage(), throwable);
          }
        });
  }

  @Override
  public void onPause() {
    super.onPause();

    // Don't kick off tasks when the app gets invisible.
    timerSubscription.unsubscribe();
  }
}

1

Per le operazioni di temporizzazione è necessario utilizzare Handler .

Se è necessario eseguire un servizio in background, AlarmManager è la strada da percorrere.


0

questo esempio avvia l'unità timer distrutta a Kotlin

private lateinit var timerTask: TimerTask

 timerTask = object : TimerTask() {
        override fun run() {
            Log.d("KTZ", "$minutes:$seconds");
            timeRecordingLiveData.postValue("$minutes:$seconds")
            seconds += 1;
            if (seconds == 60) {
                Log.d("KTZ", "$minutes:$seconds");
                timeRecordingLiveData.postValue("$minutes:$seconds")
                seconds = 0;
                minutes += 1;
            }
        }

    }

Annulla il timertask in onDestroy ()

timerTask.cancel()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.