Wie stelle ich den Timer in Android ein?


325

Kann jemand ein einfaches Beispiel für die Aktualisierung eines Textfelds jede Sekunde oder so geben?

Ich möchte einen fliegenden Ball machen und muss die Ballkoordinaten jede Sekunde berechnen / aktualisieren. Deshalb brauche ich eine Art Timer.

Ich bekomme nichts von hier .



Antworten:


463

ok, da dies noch nicht geklärt ist, gibt es 3 einfache Möglichkeiten, damit umzugehen. Unten ist ein Beispiel, das alle 3 zeigt, und unten ist ein Beispiel, das nur die Methode zeigt, die ich für vorzuziehen halte. Denken Sie auch daran, Ihre Aufgaben in onPause zu bereinigen und gegebenenfalls den Status zu speichern.


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


Das Wichtigste ist, dass die Benutzeroberfläche nur über den Haupt-UI-Thread geändert werden kann. Verwenden Sie daher einen Handler oder activity.runOnUIThread (Runnable r).

Folgendes halte ich für die bevorzugte Methode.


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, danke für das tolle Beispiel. Gibt es Vor- oder Nachteile bei der Verwendung einer Methode gegenüber den anderen, die Sie beschrieben haben?
Gautam

2
@ Gautam Ich glaube, dass alle oben genannten Methoden ungefähr gleich funktionieren. Ich persönlich bevorzuge die oben beschriebene Handler-Methode mit dem Runnable- und dem h2-Handler, da sie von der Android-Entwicklerseite vorgeschrieben und meiner Meinung nach auch die eleganteste ist.
Dave.B

6
Es wäre schön, wenn Ihre bevorzugte Methode vom Rest des Codes getrennt wäre. Als ob Sie ein Beispiel haben könnten, das Ihren bevorzugten Weg zeigt, und ein anderes, das die Alternativen zeigt. Wenn alle drei Methoden zusammen sind, ist es schwieriger zu verstehen, was los ist (insbesondere für einen Android-Neuling wie mich). Wahrscheinlich aber zu viel verlangt :)
Jesse Aldridge

4
@ JesseAldridge Gute Idee. Ich habe Code nur mit der bevorzugten Methode hinzugefügt.
Dave.B

1
@bluesm Ich habe ehrlich gesagt einfach nicht darüber nachgedacht, aber ja, das würde gut funktionieren.
Dave.B

84

Es ist einfach! Sie erstellen einen neuen Timer.

Timer timer = new Timer();

Dann erweitern Sie die Timer-Aufgabe

class UpdateBallTask extends TimerTask {
   Ball myBall;

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

Fügen Sie dann die neue Aufgabe mit einem Aktualisierungsintervall zum Timer hinzu

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

Haftungsausschluss: Dies ist nicht die ideale Lösung. Dies ist eine Lösung mit der Timer-Klasse (wie von OP gefordert). Im Android SDK wird empfohlen, die Handler-Klasse zu verwenden (die akzeptierte Antwort enthält ein Beispiel).


1
Wenn Sie den Beitrag oben lesen, werden Sie sehen, warum dies keine ideale Lösung ist
Dave.B

2
Na sicher. Das OP wollte es mit TimerTask machen, was ich nicht empfehlen werde, um im Spiel verwendet zu werden.
Fiktion

3
Huh? Das OP hat nicht angegeben, wie es gemacht werden soll. Sie haben auf einen Artikel verlinkt, in dem TimerTask verwendet wurde, aber nicht darum gebeten.
ToolmakerSteve

1
Hat viel geholfen, danke @fiction
Naveed Ahmad

1
tolle Antwort einfach zu folgen.
JMASTER B

64

Wenn Sie Ihren Code auch im UI-Thread (und nicht im Timer-Thread) ausführen müssen, schauen Sie im Blog nach: 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

    }
};
}

Der Vollständigkeit halber könnten Sie vielleicht erwähnen, was zu tun ist, um den Timer anzuhalten und ihn möglicherweise neu zu starten. (Ich fand die notwendigen Informationen hier: stackoverflow.com/questions/11550561/… )
RenniePet

3
Gibt es einen Grund, warum Sie runOnUIThread nicht direkt von der TimerTask-Ausführungsmethode aus aufrufen können? Scheint gut zu funktionieren und entfernt eine weitere Verschachtelungsebene.
RichieHH

Sicher, es ist nur eine didaktische Methode, um alle Schritte zu verstehen. Ich empfehle diesen Standard, um einen lesbaren Code zu haben.
Meir Gerenstadt

41

Wenn Sie nur einen Countdown bis zu einem späteren Zeitpunkt mit regelmäßigen Benachrichtigungen in Intervallen planen möchten, können Sie die CountDownTimer- Klasse verwenden, die seit API-Ebene 1 verfügbar ist.

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

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

2
CountDownTimer ist nur dann sinnvoll, wenn Sie wissen, dass es nach mehreren Ausführungen verschwinden soll. Dies ist kein typischer oder besonders flexibler Ansatz. Häufiger ist der Timer, der sich für immer wiederholt (den Sie abbrechen, wenn er nicht mehr benötigt wird), oder der Handler, der einmal ausgeführt wird und sich dann erneut startet, wenn er erneut benötigt wird. Siehe andere Antworten.
ToolmakerSteve

1
Du hast vollkommen Recht. Ab dem Klassennamen bietet es einen einmaligen Countdown-Timer, der bis zum Ende läuft, und natürlich verwendet es Handler in seiner Implementierung.
Ahmed Hegazy

Wie kann man auch Millisekunden anzeigen? Im Format SS:MiMi? Danke
Ruchir Baronia

26

Dies ist ein einfacher Code für einen Timer:

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

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

12

Ich denke, Sie können es auf Rx-Weise tun wie:

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

Und stornieren Sie dies wie folgt:

timerSubscribe.unsubscribe();

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


10

Da diese Frage immer noch viele Nutzer aus der Google-Suche anzieht (über den Android-Timer), möchte ich meine zwei Münzen einwerfen.

Zunächst wird die Timer- Klasse in Java 9 veraltet sein (lesen Sie die akzeptierte Antwort) .

Der offizielle empfohlene Weg ist die Verwendung von ScheduledThreadPoolExecutor, der effektiver und funktionsreicher ist und zusätzlich Befehle planen kann, die nach einer bestimmten Verzögerung ausgeführt oder regelmäßig ausgeführt werden sollen. Darüber hinaus bietet ThreadPoolExecutor zusätzliche Flexibilität und Funktionen.

Hier ist ein Beispiel für die Verwendung einfacher Funktionen.

  1. Executor Service erstellen:

    final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
  2. Planen Sie einfach, dass Sie ausgeführt werden können:

    final Future<?> future = SCHEDULER.schedule(Runnable task, long delay,TimeUnit unit);
  3. Sie können jetzt futuredie Aufgabe abbrechen oder prüfen, ob sie beispielsweise ausgeführt wurde:

    future.isDone();

Ich hoffe, Sie finden dies nützlich, um Aufgaben in Android zu erstellen.

Vollständiges Beispiel:

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

8

Ich bin überrascht, dass es keine Antwort gibt, die eine Lösung mit RxJava2 erwähnen würde . Es ist wirklich einfach und bietet eine einfache Möglichkeit, den Timer in Android einzurichten.

Zuerst müssen Sie die Gradle-Abhängigkeit einrichten, falls Sie dies noch nicht getan haben:

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

(ersetzen xund ydurch aktuelle Versionsnummer )

Da wir nur eine einfache, NICHT WIEDERHOLENDE AUFGABE haben , können wir CompletableObjekt verwenden:

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

Für REPEATING TASK können Sie Observableauf ähnliche Weise Folgendes verwenden :

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

Schedulers.computation()stellt sicher, dass unser Timer im Hintergrund-Thread ausgeführt wird, und .observeOn(AndroidSchedulers.mainThread())bedeutet, dass Code, den wir nach Ablauf des Timers ausführen, im Haupt-Thread ausgeführt wird.

Um unerwünschte Speicherverluste zu vermeiden, sollten Sie sicherstellen, dass Sie sich abmelden, wenn Aktivität / Fragment zerstört wird.


4
Dies ist der sauberste Ansatz!
Constantin

wie storniert man diese? dh wenn der Benutzer die [STOP] -Taste auf der Benutzeroberfläche drückt und der Completable vor der Ausführung abgebrochen wird.
Jemand irgendwo

@SomeoneSomewhere Speichern Sie einfach die Subscriptionzurückgegebene by- .subscribe()Methode in der Variablen und rufen subscription.unsubscribe()Sie sie auf, wenn Sie den Timer stoppen möchten.
Micer

2

Er ist eine einfachere Lösung, funktioniert gut in meiner 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

Sie möchten, dass Ihre UI-Updates im bereits vorhandenen UI-Thread erfolgen.

Der beste Weg ist, einen Handler zu verwenden, der postDelayed verwendet, um ein Runnable nach einer Verzögerung auszuführen (jeder Lauf plant den nächsten). Löschen Sie den Rückruf mit removeCallbacks.

Sie suchen bereits an der richtigen Stelle. Sehen Sie sich das noch einmal an und klären Sie vielleicht, warum dieses Codebeispiel nicht Ihren Wünschen entspricht. (Siehe auch den identischen Artikel unter Aktualisieren der Benutzeroberfläche von einem Timer ).


Leider ist Ihr Link tot. Ich kann den richtigen Artikel nicht schnell wiederfinden.
Lekensteyn

Arbeitslink hier
Risinek

1

Hier ist ein einfacher zuverlässiger Weg ...

Fügen Sie den folgenden Code in Ihre Aktivität ein, und die tick () -Methode wird jede Sekunde im UI-Thread aufgerufen, während sich Ihre Aktivität im Status "Wieder aufgenommen" befindet. Natürlich können Sie die tick () -Methode ändern, um das zu tun, was Sie wollen, oder um mehr oder weniger häufig aufgerufen zu werden.

@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());
}

Für Interessenten ist der Code "_h0 = _handler" erforderlich, um zu vermeiden, dass zwei Timer gleichzeitig ausgeführt werden, wenn Ihre Aktivität innerhalb des Tick-Zeitraums angehalten und fortgesetzt wird.


2
Warum diese peinliche _h0Ansatz, statt removeCallbacksin onPause, wie jeder andere auch?
ToolmakerSteve

1

Sie können auch einen Animator dafür verwenden:

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

Sie müssen einen Thread erstellen, um die Aktualisierungsschleife zu verarbeiten, und ihn zum Aktualisieren des Textbereichs verwenden. Der schwierige Teil ist jedoch, dass nur der Haupt-Thread die Benutzeroberfläche tatsächlich ändern kann, sodass der Update-Loop-Thread dem Haupt-Thread signalisieren muss, das Update durchzuführen. Dies erfolgt mit einem Handler.

Schauen Sie sich diesen Link an: http://developer.android.com/guide/topics/ui/dialogs.html# Klicken Sie auf den Abschnitt "Beispiel für einen Fortschrittsdialog mit einem zweiten Thread". Dies ist ein Beispiel dafür, was genau Sie tun müssen, außer mit einem Fortschrittsdialog anstelle eines Textfelds.


Tu das nicht. Es gibt eine einfache Timer-Klasse, die dies alles für Sie erledigt. Und diese Frage hat überhaupt nichts mit Fortschrittsdialogen oder Dialogen zu tun.
Falmarri

Haben Sie sich den Abschnitt des Links angesehen, den ich gepostet habe, oder haben Sie nur den Wortdialog gesehen und angenommen? Der Code dort ist 100% relevant. Wenn Sie einen Timer verwenden, erstellen Sie immer noch einen Thread, um die Aktualisierungsschleife zu verarbeiten. Sie müssen den Handler weiterhin wie in dem von mir geposteten Link beschrieben verwenden.
Nick

Leider enthält die verlinkte Seite keinen Abschnitt mehr mit dem genannten Titel. Wenn Sie auf Code verlinken, sollten Sie immer den Schlüsselausschnitt direkt in Ihre Antwort aufnehmen.
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
Vielleicht wären einige Codeeinrückungen und Codeerklärungen hilfreich.
Raul Rene

0

Wenn jemand interessiert ist, habe ich angefangen, ein Standardobjekt zu erstellen, das auf einem Aktivitäts-UI-Thread ausgeführt werden soll. Scheint in Ordnung zu funktionieren. Kommentare willkommen. Ich würde es lieben, wenn dies im Layout-Designer als Komponente zum Ziehen auf eine Aktivität verfügbar wäre. Ich kann nicht glauben, dass so etwas noch nicht existiert.

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

In der Aktivität habe ich diesen onStart:

@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
Alter, was ist los mit dem ActivityTimerListener? Mein ADT-Bundle sagte, dass es keine solche Klasse gibt.
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"/>


Ich sehe, dass Sie dies einige Jahre nach der ursprünglichen Frage und den Antworten hinzugefügt haben. Bitte fügen Sie eine Erklärung hinzu, wie diese Antwort mit anderen Antworten verglichen wird, die bereits vorhanden waren. Warum haben Sie einen weiteren hinzugefügt - welchen Nutzen / wann nützlich / welchen Mangel haben Sie in anderen Antworten gesehen?
ToolmakerSteve

Ich teile nur einen Code, der dieselbe Arbeit mit einem anderen Ansatz ausführt. Aber wann immer Sie die Daten einer Ansicht aktualisieren möchten. Sie müssen den Handler dafür verwenden. weil ich oft bemerkt habe, dass die Verwendung einer Zeitaufgabe zum Aktualisieren einer Ansicht nicht funktioniert. Die @ Dave.B-Methode ist meines Wissens korrekter.
Zar E Ahmer

0

Wenn Sie bereits Deltazeit haben.

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

Ich abstrahiere Timer weg und mache es zu einer separaten Klasse:

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

Und extrahieren Sie die Hauptaktion aus der TimerKlasse als

IAction.java

public interface IAction {
    void Task();
}

Und ich habe es einfach so benutzt:

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++;
        }
    });
}
...
}

Ich hoffe das hilft 😊👌


0

Ich benutze diesen Weg:

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

dann unter dem 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();

Es ist ein einfacher Weg, um dieses Problem zu lösen.


0

Für diejenigen, die sich nicht auf Chronometer verlassen können , habe ich aus einem der Vorschläge eine Utility-Klasse erstellt:

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

zu verwenden .. nur tun:

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

..... .....

 timerTextHelper.stop();
 long elapsedTime = timerTextHelper.getElapsedTime();
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.