Come impostare il timer in Android?


325

Qualcuno può dare un semplice esempio di aggiornamento di un campo di testo ogni secondo o giù di lì?

Voglio creare una palla volante e ho bisogno di calcolare / aggiornare le coordinate della palla ogni secondo, ecco perché ho bisogno di una sorta di timer.

Non capisco niente da qui .



Risposte:


463

ok dato che questo non è stato chiarito, ma ci sono 3 semplici modi per gestirlo. Di seguito è riportato un esempio che mostra tutti e 3 e in basso un esempio che mostra solo il metodo che ritengo sia preferibile. Ricorda anche di ripulire le tue attività in onPause, salvando lo stato se necessario.


import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Handler.Callback;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class main extends Activity {
    TextView text, text2, text3;
    long starttime = 0;
    //this  posts a message to the main thread from our timertask
    //and updates the textfield
   final Handler h = new Handler(new Callback() {

        @Override
        public boolean handleMessage(Message msg) {
           long millis = System.currentTimeMillis() - starttime;
           int seconds = (int) (millis / 1000);
           int minutes = seconds / 60;
           seconds     = seconds % 60;

           text.setText(String.format("%d:%02d", minutes, seconds));
            return false;
        }
    });
   //runs without timer be reposting self
   Handler h2 = new Handler();
   Runnable run = new Runnable() {

        @Override
        public void run() {
           long millis = System.currentTimeMillis() - starttime;
           int seconds = (int) (millis / 1000);
           int minutes = seconds / 60;
           seconds     = seconds % 60;

           text3.setText(String.format("%d:%02d", minutes, seconds));

           h2.postDelayed(this, 500);
        }
    };

   //tells handler to send a message
   class firstTask extends TimerTask {

        @Override
        public void run() {
            h.sendEmptyMessage(0);
        }
   };

   //tells activity to run on ui thread
   class secondTask extends TimerTask {

        @Override
        public void run() {
            main.this.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                   long millis = System.currentTimeMillis() - starttime;
                   int seconds = (int) (millis / 1000);
                   int minutes = seconds / 60;
                   seconds     = seconds % 60;

                   text2.setText(String.format("%d:%02d", minutes, seconds));
                }
            });
        }
   };


   Timer timer = new Timer();
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        text = (TextView)findViewById(R.id.text);
        text2 = (TextView)findViewById(R.id.text2);
        text3 = (TextView)findViewById(R.id.text3);

        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
        b.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Button b = (Button)v;
                if(b.getText().equals("stop")){
                    timer.cancel();
                    timer.purge();
                    h2.removeCallbacks(run);
                    b.setText("start");
                }else{
                    starttime = System.currentTimeMillis();
                    timer = new Timer();
                    timer.schedule(new firstTask(), 0,500);
                    timer.schedule(new secondTask(),  0,500);
                    h2.postDelayed(run, 0);
                    b.setText("stop");
                }
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();
        timer.cancel();
        timer.purge();
        h2.removeCallbacks(run);
        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
    }
}


la cosa principale da ricordare è che l'IU può essere modificata solo dal thread principale dell'interfaccia utente, quindi usa un gestore o activity.runOnUIThread (Runnable r);

Ecco quello che considero il metodo preferito.


import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class TestActivity extends Activity {

    TextView timerTextView;
    long startTime = 0;

    //runs without a timer by reposting this handler at the end of the runnable
    Handler timerHandler = new Handler();
    Runnable timerRunnable = new Runnable() {

        @Override
        public void run() {
            long millis = System.currentTimeMillis() - startTime;
            int seconds = (int) (millis / 1000);
            int minutes = seconds / 60;
            seconds = seconds % 60;

            timerTextView.setText(String.format("%d:%02d", minutes, seconds));

            timerHandler.postDelayed(this, 500);
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_activity);

        timerTextView = (TextView) findViewById(R.id.timerTextView);

        Button b = (Button) findViewById(R.id.button);
        b.setText("start");
        b.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Button b = (Button) v;
                if (b.getText().equals("stop")) {
                    timerHandler.removeCallbacks(timerRunnable);
                    b.setText("start");
                } else {
                    startTime = System.currentTimeMillis();
                    timerHandler.postDelayed(timerRunnable, 0);
                    b.setText("stop");
                }
            }
        });
    }

  @Override
    public void onPause() {
        super.onPause();
        timerHandler.removeCallbacks(timerRunnable);
        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
    }

}



1
@ Dave.B, grazie per l'ottimo esempio. Ci sono vantaggi / svantaggi nell'usare un metodo rispetto agli altri che hai delineato?
Gautam,

2
@Gautam Credo che tutti i metodi sopra descritti funzionino allo stesso modo. Personalmente preferisco il metodo del gestore descritto sopra con Runnable e h2 Handler in quanto è quello prescritto dal sito degli sviluppatori Android e secondo me anche il più elegante.
Dave.B,

6
Sarebbe bello avere il tuo metodo preferito separato dal resto del codice. Come se potessi avere un esempio che mostra il tuo modo preferito e un altro che mostra le alternative. Avere tutti e tre i metodi insieme rende più difficile capire cosa sta succedendo (specialmente per un neofita Android come me). Probabilmente chiedo troppo però :)
Jesse Aldridge,

4
@JesseAldridge Buona idea. Sono andato avanti e ho aggiunto il codice solo con il metodo preferito.
Dave.B,

1
@bluesm Onestamente non ci ho pensato, ma sì, avrebbe funzionato bene.
Dave.B,

84

È semplice! Si crea un nuovo timer.

Timer timer = new Timer();

Quindi estendi l'attività timer

class UpdateBallTask extends TimerTask {
   Ball myBall;

   public void run() {
       //calculate the new position of myBall
   }
}

Quindi aggiungi la nuova attività al Timer con un intervallo di aggiornamento

final int FPS = 40;
TimerTask updateBall = new UpdateBallTask();
timer.scheduleAtFixedRate(updateBall, 0, 1000/FPS);

Disclaimer: questa non è la soluzione ideale. Questa è una soluzione che utilizza la classe Timer (come richiesto dall'OP). In Android SDK, si consiglia di utilizzare la classe Handler (c'è un esempio nella risposta accettata).


1
se leggi il post sopra vedrai perché questa non è una soluzione ideale
Dave.B,

2
Ovviamente. L'OP voleva farlo con TimerTask, che non consiglierò di usare nel gioco.
fiction

3
Eh? L'OP non ha specificato come lo desideravano. Hanno collegato a un articolo che utilizzava TimerTask, ma non hanno richiesto che fosse fatto in quel modo.
ToolmakerSteve,

1
Aiutato molto, grazie @fiction
Naveed Ahmad,

1
ottima risposta semplice da seguire.
JMASTER B,

64

Se devi anche eseguire il codice sul thread dell'interfaccia utente (e non sul thread del timer), dai un'occhiata al blog: http://steve.odyfamily.com/?p=12

public class myActivity extends Activity {
private Timer myTimer;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);

    myTimer = new Timer();
    myTimer.schedule(new TimerTask() {          
        @Override
        public void run() {
            TimerMethod();
        }

    }, 0, 1000);
}

private void TimerMethod()
{
    //This method is called directly by the timer
    //and runs in the same thread as the timer.

    //We call the method that will work with the UI
    //through the runOnUiThread method.
    this.runOnUiThread(Timer_Tick);
}


private Runnable Timer_Tick = new Runnable() {
    public void run() {

    //This method runs in the same thread as the UI.               

    //Do something to the UI thread here

    }
};
}

Per completezza potresti forse menzionare cosa fare per fermare il timer e magari riavviarlo. (Ho trovato le informazioni necessarie qui: stackoverflow.com/questions/11550561/... )
RenniePet

3
C'è qualche motivo per cui non puoi semplicemente chiamare runOnUIThread direttamente dal metodo di esecuzione TimerTask? Sembra funzionare bene e rimuove un altro livello di annidamento.
RichieHH,

Certo, è solo un metodo didattico per comprendere tutti i passaggi. Suggerisco a questo standard di avere un codice leggibile.
Meir Gerenstadt,

41

Se si desidera solo programmare un conto alla rovescia fino a un certo momento in futuro con notifiche regolari a intervalli lungo il percorso, è possibile utilizzare la classe CountDownTimer disponibile dal livello API 1.

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

    public void onFinish() {
        editText.setText("Done");
    }
}.start();

2
CountDownTimer ha senso solo se sai che vuoi che scompaia dopo diverse esecuzioni. Questo non è un approccio tipico, né particolarmente flessibile. Più comune è il timer che si ripete per sempre (che si annulla quando non è più necessario) o il gestore che viene eseguito una volta, quindi si riavvia se sarà necessario di nuovo. Vedi altre risposte
ToolmakerSteve

1
Hai perfettamente ragione. Dal nome della classe fornisce un conto alla rovescia del conto alla rovescia fino al termine e, naturalmente, utilizza Handler nella sua implementazione.
Ahmed Hegazy

Come mostrare anche i millisecondi? Nel formato SS:MiMi? Grazie
Ruchir Baronia il

26

Questo è un semplice codice per un timer:

Timer timer = new Timer();
TimerTask t = new TimerTask() {       
    @Override
    public void run() {

        System.out.println("1");
    }
};
timer.scheduleAtFixedRate(t,1000,1000);

12

Penso che tu possa farlo in modo Rx come:

 timerSubscribe = Observable.interval(1, TimeUnit.SECONDS)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1<Long>() {
                @Override
                public void call(Long aLong) {
                      //TODO do your stuff
                }
            });

E cancella questo tipo:

timerSubscribe.unsubscribe();

Rx Timer http://reactivex.io/documentation/operators/timer.html


10

Poiché questa domanda sta ancora attirando molti utenti dalla ricerca di Google (sul timer di Android), vorrei inserire le mie due monete.

Prima di tutto, la classe Timer sarà deprecata in Java 9 (leggi la risposta accettata) .

Il modo suggerito ufficiale è utilizzare ScheduledThreadPoolExecutor che è più efficace e ricco di funzionalità che può inoltre programmare l'esecuzione dei comandi dopo un determinato ritardo o l'esecuzione periodica. Inoltre, offre ulteriore flessibilità e funzionalità di ThreadPoolExecutor.

Ecco un esempio di utilizzo di funzionalità semplici.

  1. Crea servizio esecutori:

    final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
  2. Pianifica il tuo runnable:

    final Future<?> future = SCHEDULER.schedule(Runnable task, long delay,TimeUnit unit);
  3. Ora puoi utilizzare futureper annullare l'attività o verificare se è stata eseguita, ad esempio:

    future.isDone();

Spero che lo troverai utile per creare attività in Android.

Esempio completo:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Future<?> sampleFutureTimer = scheduler.schedule(new Runnable(), 120, TimeUnit.SECONDS);
if (sampleFutureTimer.isDone()){
    // Do something which will save world.
}

8

Sono sorpreso che non vi sia alcuna risposta che menzioni la soluzione con RxJava2 . È davvero semplice e offre un modo semplice per impostare il timer in Android.

Per prima cosa devi impostare la dipendenza Gradle, se non l'hai già fatto:

implementation "io.reactivex.rxjava2:rxjava:2.x.y"

(sostituire xe ycon il numero di versione corrente )

Dato che abbiamo solo un TASK semplice, NON RIPETENTE , possiamo usare l' Completableoggetto:

Completable.timer(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(() -> {
            // Timer finished, do something...
        });

Per REPEATING TASK , è possibile utilizzare Observablein modo simile:

Observable.interval(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(tick -> {
            // called every 2 seconds, do something...
        }, throwable -> {
            // handle error
        });

Schedulers.computation() assicura che il nostro timer sia in esecuzione su thread in background e .observeOn(AndroidSchedulers.mainThread()) significa che il codice che eseguiamo dopo la fine del timer verrà eseguito sul thread principale.

Per evitare perdite di memoria indesiderate, è necessario assicurarsi di annullare l'iscrizione in caso di distruzione di Attività / Frammento.


4
Questo è l'approccio più pulito!
Costantinopoli,

come si cancellano questi? cioè quando l'utente preme il pulsante [STOP] sull'interfaccia utente e il Completabile viene annullato prima dell'esecuzione.
Someone Somewhere,

@SomeoneSomewhere Basta salvare il metodo Subscriptionrestituito dalla .subscribe()variabile e quindi chiamare subscription.unsubscribe()quando si desidera arrestare il timer.
Micer,

2

È una soluzione più semplice, funziona bene nella mia app.

  public class MyActivity extends Acitivity {

    TextView myTextView;
    boolean someCondition=true;

     @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.my_activity);

            myTextView = (TextView) findViewById(R.id.refreshing_field);

            //starting our task which update textview every 1000 ms
            new RefreshTask().execute();



        }

    //class which updates our textview every second

    class RefreshTask extends AsyncTask {

            @Override
            protected void onProgressUpdate(Object... values) {
                super.onProgressUpdate(values);
                String text = String.valueOf(System.currentTimeMillis());
                myTextView.setText(text);

            }

            @Override
            protected Object doInBackground(Object... params) {
                while(someCondition) {
                    try {
                        //sleep for 1s in background...
                        Thread.sleep(1000);
                        //and update textview in ui thread
                        publishProgress();
                    } catch (InterruptedException e) {
                        e.printStackTrace(); 

                };
                return null;
            }
        }
    }

2

Si desidera che gli aggiornamenti dell'interfaccia utente vengano eseguiti nel thread dell'interfaccia utente già esistente.

Il modo migliore è utilizzare un gestore che utilizza postDelayed per eseguire un Runnable dopo un ritardo (ogni esecuzione pianifica la successiva); cancella il callback con removeCallbacks.

Stai già guardando nel posto giusto, quindi guardalo di nuovo, forse chiarisci perché questo esempio di codice non è quello che vuoi. (Vedi anche l'articolo identico in Aggiornamento dell'interfaccia utente da un timer ).


Sfortunatamente, il tuo link è morto. Non riesco a trovare rapidamente l'articolo corretto.
Lekensteyn,


1

Ecco un modo semplice e affidabile ...

Inserisci il seguente codice nella tua attività e il metodo tick () verrà chiamato ogni secondo nel thread dell'interfaccia utente mentre la tua attività è nello stato "ripreso". Ovviamente, puoi cambiare il metodo tick () per fare quello che vuoi o essere chiamato più o meno frequentemente.

@Override
public void onPause() {
    _handler = null;
    super.onPause();
}

private Handler _handler;

@Override
public void onResume() {
    super.onResume();
    _handler = new Handler();
    Runnable r = new Runnable() {
        public void run() {
            if (_handler == _h0) {
                tick();
                _handler.postDelayed(this, 1000);
            }
        }

        private final Handler _h0 = _handler;
    };
    r.run();
}

private void tick() {
    System.out.println("Tick " + System.currentTimeMillis());
}

Per coloro che sono interessati, il codice "_h0 = _handler" è necessario per evitare che due timer vengano eseguiti simultaneamente se la tua attività viene messa in pausa e ripresa entro il periodo di tick.


2
Perché questo _h0approccio imbarazzante , anziché removeCallbacksin onPause, come tutti gli altri?
ToolmakerSteve,

1

Puoi anche usare un animatore per questo:

int secondsToRun = 999;

ValueAnimator timer = ValueAnimator.ofInt(secondsToRun);
timer.setDuration(secondsToRun * 1000).setInterpolator(new LinearInterpolator());
timer.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
    {
        @Override
        public void onAnimationUpdate(ValueAnimator animation)
        {
            int elapsedSeconds = (int) animation.getAnimatedValue();
            int minutes = elapsedSeconds / 60;
            int seconds = elapsedSeconds % 60;

            textView.setText(String.format("%d:%02d", minutes, seconds));
        }
    });
timer.start();

0

È necessario creare un thread per gestire il ciclo di aggiornamento e utilizzarlo per aggiornare l'area di testo. La parte difficile è che solo il thread principale può effettivamente modificare l'interfaccia utente, quindi il thread del ciclo di aggiornamento deve segnalare il thread principale per eseguire l'aggiornamento. Questo viene fatto usando un gestore.

Dai un'occhiata a questo link: http://developer.android.com/guide/topics/ui/dialogs.html# Fai clic sulla sezione "Esempio ProgressDialog con un secondo thread". È un esempio esattamente di ciò che devi fare, tranne che con una finestra di avanzamento anziché un campo di testo.


Non farlo C'è una semplice classe di timer che fa tutto questo per te. E questa domanda non ha assolutamente nulla a che fare con i dialoghi o le finestre di dialogo.
Falmarri,

Hai guardato la sezione del link che ho pubblicato o hai appena visto la parola dialog e hai assunto? Il codice è rilevante al 100%. Inoltre, se si utilizza il timer, si sta ancora creando un thread per gestire il ciclo di aggiornamento. Dovrai comunque utilizzare il gestore come descritto nel link che ho pubblicato.
Nick,

Sfortunatamente, la pagina collegata non contiene più una sezione con il titolo menzionato. Quando si collega al codice, si dovrebbe sempre includere lo snippet chiave direttamente nella risposta.
ToolmakerSteve,

0
void method(boolean u,int max)
{
    uu=u;
    maxi=max;
    if (uu==true)
    { 
        CountDownTimer uy = new CountDownTimer(maxi, 1000) 
  {
            public void onFinish()
            {
                text.setText("Finish"); 
            }

            @Override
            public void onTick(long l) {
                String currentTimeString=DateFormat.getTimeInstance().format(new Date());
                text.setText(currentTimeString);
            }
        }.start();
    }

    else{text.setText("Stop ");
}

2
Forse alcuni rientri del codice e spiegazioni del codice sarebbero utili.
Raul Rene

0

Se qualcuno è interessato, ho iniziato a giocare con la creazione di un oggetto standard da eseguire su un thread dell'interfaccia utente delle attività. Sembra funzionare bene. Commenti benvenuti. Mi piacerebbe che fosse disponibile sul progettista del layout come componente da trascinare su un'attività. Non riesco a credere che qualcosa del genere non esista già.

package com.example.util.timer;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;

public class ActivityTimer {

    private Activity m_Activity;
    private boolean m_Enabled;
    private Timer m_Timer;
    private long m_Delay;
    private long m_Period;
    private ActivityTimerListener m_Listener;
    private ActivityTimer _self;
    private boolean m_FireOnce;

    public ActivityTimer() {
        m_Delay = 0;
        m_Period = 100;
        m_Listener = null;
        m_FireOnce = false;
        _self = this;
    }

    public boolean isEnabled() {
        return m_Enabled;
    }

    public void setEnabled(boolean enabled) {
        if (m_Enabled == enabled)
            return;

        // Disable any existing timer before we enable a new one
        Disable();

        if (enabled) {
            Enable();
        }
    }

    private void Enable() {
        if (m_Enabled)
            return;

        m_Enabled = true;

        m_Timer = new Timer();
        if (m_FireOnce) {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay);
        } else {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay, m_Period);
        }
    }

    private void Disable() {
        if (!m_Enabled)
            return;

        m_Enabled = false;

        if (m_Timer == null)
            return;

        m_Timer.cancel();
        m_Timer.purge();
        m_Timer = null;
    }

    private void OnTick() {
        if (m_Activity != null && m_Listener != null) {
            m_Activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    m_Listener.OnTimerTick(m_Activity, _self);
                }
            });
        }
        if (m_FireOnce)
            Disable();
    }

    public long getDelay() {
        return m_Delay;
    }

    public void setDelay(long delay) {
        m_Delay = delay;
    }

    public long getPeriod() {
        return m_Period;
    }

    public void setPeriod(long period) {
        if (m_Period == period)
            return;
        m_Period = period;
    }

    public Activity getActivity() {
        return m_Activity;
    }

    public void setActivity(Activity activity) {
        if (m_Activity == activity)
            return;
        m_Activity = activity;
    }

    public ActivityTimerListener getActionListener() {
        return m_Listener;
    }

    public void setActionListener(ActivityTimerListener listener) {
        m_Listener = listener;
    }

    public void start() {
        if (m_Enabled)
            return;
        Enable();
    }

    public boolean isFireOnlyOnce() {
        return m_FireOnce;
    }

    public void setFireOnlyOnce(boolean fireOnce) {
        m_FireOnce = fireOnce;
    }
}

Nell'attività, ho questo su Start:

@Override
protected void onStart() {
    super.onStart();

    m_Timer = new ActivityTimer();
    m_Timer.setFireOnlyOnce(true);
    m_Timer.setActivity(this);
    m_Timer.setActionListener(this);
    m_Timer.setDelay(3000);
    m_Timer.start();
}

1
amico, cosa c'è che non va con ActivityTimerListener? Il mio pacchetto ADT ha affermato che non esiste tale classe.
Sorokin Andrey,

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

 }

}

.xml

<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"/>


Vedo che l'hai aggiunto diversi anni dopo la domanda e le risposte originali. Aggiungi una spiegazione di come questa risposta si confronta con altre risposte che erano già lì. Perché ne hai aggiunto un altro: quali vantaggi / quando utili / quali carenze hai riscontrato nelle altre risposte?
ToolmakerSteve,

Condivido solo un codice che sta facendo lo stesso lavoro con un approccio diverso. Ma ogni volta che vuoi aggiornare i dati di una vista. È necessario utilizzare il gestore per questo. perché molte volte ho notato che l'uso di un timertask per aggiornare una vista non funziona .. Il metodo @ Dave.B è più corretto per quanto ne sappia.
Zar E Ahmer,

0

Se hai già delta time.

public class Timer {
    private float lastFrameChanged;
    private float frameDuration;
    private Runnable r;

    public Timer(float frameDuration, Runnable r) {
        this.frameDuration = frameDuration;
        this.lastFrameChanged = 0;
        this.r = r;
    }

    public void update(float dt) {
        lastFrameChanged += dt;

        if (lastFrameChanged > frameDuration) {
            lastFrameChanged = 0;
            r.run();
        }
    }
}

0

Ho estratto il timer e l'ho reso una classe separata:

Timer.java

import android.os.Handler;

public class Timer {

    IAction action;
    Handler timerHandler = new Handler();
    int delayMS = 1000;

    public Timer(IAction action, int delayMS) {
        this.action = action;
        this.delayMS = delayMS;
    }

    public Timer(IAction action) {
        this(action, 1000);
    }

    public Timer() {
        this(null);
    }

    Runnable timerRunnable = new Runnable() {

        @Override
        public void run() {
            if (action != null)
                action.Task();
            timerHandler.postDelayed(this, delayMS);
        }
    };

    public void start() {
        timerHandler.postDelayed(timerRunnable, 0);
    }

    public void stop() {
        timerHandler.removeCallbacks(timerRunnable);
    }
}

Ed Estrai l'azione principale dalla Timerclasse come

IAction.java

public interface IAction {
    void Task();
}

E l'ho usato così:

MainActivity.java

public class MainActivity extends Activity implements IAction{
...
Timer timerClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
        ...
        timerClass = new Timer(this,1000);
        timerClass.start();
        ...
}
...
int i = 1;
@Override
public void Task() {
    runOnUiThread(new Runnable() {

        @Override
        public void run() {
            timer.setText(i + "");
            i++;
        }
    });
}
...
}

Spero che questo aiuti 😊👌


0

Uso in questo modo:

String[] array={
       "man","for","think"
}; int j;

quindi sotto onCreate

TextView t = findViewById(R.id.textView);

    new CountDownTimer(5000,1000) {

        @Override
        public void onTick(long millisUntilFinished) {}

        @Override
        public void onFinish() {
            t.setText("I "+array[j] +" You");
            j++;
            if(j== array.length-1) j=0;
            start();
        }
    }.start();

è un modo semplice per risolvere questo problema.


0

Per coloro che non possono fare affidamento su Chronometer , ho creato una classe di utilità da uno dei suggerimenti:

public class TimerTextHelper implements Runnable {
   private final Handler handler = new Handler();
   private final TextView textView;
   private volatile long startTime;
   private volatile long elapsedTime;

   public TimerTextHelper(TextView textView) {
       this.textView = textView;
   }

   @Override
   public void run() {
       long millis = System.currentTimeMillis() - startTime;
       int seconds = (int) (millis / 1000);
       int minutes = seconds / 60;
       seconds = seconds % 60;

       textView.setText(String.format("%d:%02d", minutes, seconds));

       if (elapsedTime == -1) {
           handler.postDelayed(this, 500);
       }
   }

   public void start() {
       this.startTime = System.currentTimeMillis();
       this.elapsedTime = -1;
       handler.post(this);
   }

   public void stop() {
       this.elapsedTime = System.currentTimeMillis() - startTime;
       handler.removeCallbacks(this);
   }

   public long getElapsedTime() {
       return elapsedTime;
   }
 }

da usare ... basta fare:

 TimerTextHelper timerTextHelper = new TimerTextHelper(textView);
 timerTextHelper.start();

.....

 timerTextHelper.stop();
 long elapsedTime = timerTextHelper.getElapsedTime();
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.