Wie man einen Timer in Android einstellt

172

Was ist der richtige Weg, um einen Timer in Android einzustellen, um eine Aufgabe zu starten (eine Funktion, die ich erstelle und die die Benutzeroberfläche nicht ändert)? Verwenden Sie dies auf Java-Weise: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html

Oder gibt es einen besseren Weg in Android (Android-Handler)?

n179911
quelle

Antworten:

143

Die Standardmethode von Java zur Verwendung von Timern über java.util.Timer und java.util.TimerTask funktioniert in Android einwandfrei. Sie sollten sich jedoch bewusst sein, dass diese Methode einen neuen Thread erstellt.

Sie können die sehr praktische Handler- Klasse (android.os.Handler) verwenden und Nachrichten über sendMessageAtTime(android.os.Message, long)oder an den Handler senden sendMessageDelayed(android.os.Message, long). Sobald Sie eine Nachricht erhalten haben, können Sie die gewünschten Aufgaben ausführen. Die zweite Möglichkeit wäre, ein ausführbares Objekt zu erstellen und es über die Handler-Funktionen postAtTime(java.lang.Runnable, long)oder zu planen postDelayed(java.lang.Runnable, long).

MannyNS
quelle
10
Dies ist der falsche Weg, um Dinge in Android zu tun. In Android möchten Sie den Alarm Manager (developer.android.com/reference/android/app/AlarmManager.html) verwenden, um Aufgaben weit in der Zukunft auszuführen.
Kurtis Nusbaum
9
@ Kurtis Nusbaum Die Frage sagt nicht, wie weit die Aufgabe in der Zukunft ist.
Christopher Perry
67
@ KurtisNusbaum Das stimmt nicht unbedingt, es kommt auf den Kontext an. In den Dokumenten zu AlarmManager heißt es: "Hinweis: Der Alarm Manager ist für Fälle vorgesehen, in denen Ihr Anwendungscode zu einem bestimmten Zeitpunkt ausgeführt werden soll, auch wenn Ihre Anwendung derzeit nicht ausgeführt wird. Für normale Zeitsteuerungsvorgänge (Ticks, Zeitüberschreitungen usw.) Die Verwendung von Handler ist einfacher und effizienter. "
Christopher Perry
5
@ Science Prodigy Ah, ich verstehe. Meinetwegen.
Kurtis Nusbaum
10
Die Verwendung der Handler-Methode zum Planen einer Aufgabe ist nur dann zuverlässig, wenn die Anwendung ein WakeLock erworben hat und Sie daher sicher sind, dass das Telefon nicht in den Ruhezustand versetzt wird. Wenn das Telefon in den Ruhezustand wechselt, funktionieren sendMessageDelayed und sendMessageAtTime nicht. Daher wäre AlarmManager in diesem Szenario eine zuverlässige Wahl.
crazyaboutliv
159

ja javas timer kann verwendet werden , aber wie die frage nach einem besseren weg fragt (für mobile). Welche erklärt hier .


Für StackOverflow:

Da Timer einen neuen Thread erstellt, kann dieser als schwer angesehen werden.

Wenn Sie nur einen Rückruf benötigen, während die Aktivität ausgeführt wird, kann ein Handler in Verbindung mit a verwendet werden

Runnable :

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

oder eine Nachricht

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

Nebenbei bemerkt kann dieser Ansatz verwendet werden, wenn Sie einen Code im UI-Thread von einem anderen Thread ausführen möchten.

Wenn Sie einen Rückruf benötigen, auch wenn Ihre Aktivität nicht ausgeführt wird, können Sie einen AlarmManager verwenden

Samuel
quelle
1
Oh ja, ich habe genau diese Antwort gegoogelt. Nehmen Sie meine Gegenstimme für den nützlichen Link.
Ulidtko
1
hat den Link aktualisiert und spricht darüber, dass Google Probleme beim Verwalten von Links hat.
Samuel
1
Dieser Artikel aus dem Jahr 2007 - ohne zu sagen, dass er falsch ist, aber ich bin immer misstrauisch gegenüber einem mobilen Artikel, wenn er älter als 3 Jahre ist. Die Dinge ändern sich ziemlich schnell.
StackOverflowed
1
Es wäre eher wie bei StackOverflow, wenn Sie die Hauptpunkte Ihres Links hier in Ihrer Antwort zitieren könnten.
n611x007
1
@naxa, meine zwei Cent, um diese Antwort eher wie StackOverflow zu machen.
Samuel
131

Wie ich gesehen habe, wird java.util.Timer am häufigsten zum Implementieren eines Timers verwendet.

Für eine sich wiederholende Aufgabe:

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

Für einen einzelnen Durchlauf einer Aufgabe:

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


Aufgabe ist die Methode, die
nach der Zeit bis zur ersten Ausführung ausgeführt werden soll
( Intervall die Zeit für die Wiederholung der Ausführung)

Thizzer
quelle
9
Ich füge nur hinzu, dass die Zeit in Millisekunden ist
Uri
2
Android Dev Docs für ScheduleAtFixedRate
N611x007
1
taskMöglicherweise handelt es sich um eine Instanz Ihrer Klasse, die von java.util.TimerTask erbt und überschreibt void run().
n611x007
2
So viele positive Stimmen. Sie könnten dazu. Aber @Samuel beschreibt den besseren Weg. Unter seinem Link "Was hier erklärt wird" erfahren Sie, warum. Kann die Benutzeroberfläche auch nicht über einen Timer-Thread aktualisieren! Und sieht diese Handler basierten Antworten in anderen Threads: (einfach) stackoverflow.com/a/6702767/199364 oder (zeigen verschiedene Alternativen) stackoverflow.com/a/4598737/199364
ToolmakerSteve
@quemeful, weil es nicht immer um Bequemlichkeit geht, sondern um Codequalität und Effizienz. Diese Art und Weise
verbraucht
33

Ich hoffe, dieser ist hilfreich und erfordert möglicherweise weniger Aufwand bei der Implementierung der Android CountDownTimer-Klasse

z.B

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

      public void onFinish() {
          mTextField.setText("done!");
      }  
}.start();
Gaurav Adurkar
quelle
1
Dies ist am einfachsten und trifft direkt auf den Kopf für einen einfachen Countdown wie ein Beginn der Video-Wiedergabe
Vijay Kumar Kanta
17

Wahrscheinlich 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();

oder

Methode 2 ::

Programmieren Sie den Timer

Fügen Sie eine neue Variable mit dem Namen int time hinzu. Setzen Sie es auf 0. Fügen Sie der Funktion onCreate in MainActivity.java den folgenden Code hinzu.

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

Gehen Sie in die Ausführungsmethode und fügen Sie den folgenden Code hinzu.

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

});
vkulkarni
quelle
11

Es ist situativ.

In der Android-Dokumentation wird empfohlen , AlarmManager zu verwenden, um eine Absicht zu registrieren, die zum angegebenen Zeitpunkt ausgelöst wird , wenn Ihre Anwendung möglicherweise nicht ausgeführt wird.

Andernfalls sollten Sie Handler verwenden.

Hinweis: Der Alarm Manager ist für Fälle vorgesehen, in denen Ihr Anwendungscode zu einem bestimmten Zeitpunkt ausgeführt werden soll, auch wenn Ihre Anwendung derzeit nicht ausgeführt wird. Für normale Timing-Vorgänge (Ticks, Timeouts usw.) ist die Verwendung von Handler einfacher und effizienter.

Timothy Lee Russell
quelle
11

Los geht's. Wir brauchen zwei Klassen. Ich poste einen Code, der das mobile Audioprofil alle 5 Sekunden (5000 Millisekunden) ändert ...

Unsere 1. Klasse

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

}

Unsere 2. Klasse

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

    }

}
Rizwan Sohaib
quelle
5

Ich bin ein Android-Neuling, aber hier ist die Timer-Klasse, die ich basierend auf den obigen Antworten erstellt habe. Es funktioniert für meine App, aber ich freue mich über Vorschläge.

Anwendungsbeispiel:

...{
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);
        }
    }; 
}
user868020
quelle
3

Ich verwende einen Handler und kann ausgeführt werden, um einen Timer zu erstellen. Ich verpacke dies in eine abstrakte Klasse. Leiten Sie es einfach ab / implementieren Sie es und Sie können loslegen:

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

Beachten Sie, dass der handler.postDelayedvor dem auszuführenden Code aufgerufen wird. Dadurch wird der Timer zeitlich geschlossener als erwartet. In Fällen, in denen der Timer zu häufig läuft und die Aufgabe ( onTimer()) lang ist, kann es zu Überlappungen kommen. Wenn Sie intervalMSnach Abschluss der Aufgabe mit dem Zählen beginnen möchten , verschieben Sie den onTimer()Anruf um eine Zeile darüber.

elcuco
quelle
2

Ich glaube, der Weg, dies auf dem Android zu tun, ist, dass Sie einen Hintergrunddienst benötigen, um ausgeführt zu werden. Erstellen Sie in dieser Hintergrundanwendung den Timer. Wenn der Timer "tickt" (legen Sie das Intervall fest, wie lange Sie warten möchten), starten Sie Ihre Aktivität, die Sie starten möchten.

http://developer.android.com/guide/topics/fundamentals.html (<- In diesem Artikel wird die Beziehung zwischen Aktivitäten, Diensten, Absichten und anderen grundlegenden Grundlagen der Android-Entwicklung erläutert.)

Crowe T. Robot
quelle
1

Ich habe ( Timer, TimerTask) verwendet Handlerund (zeitaufwändige) Aufgaben regelmäßig gestartet. Jetzt habe ich das ganze auf RxJava umgestellt. RxJava bietet Observable.timereine einfachere, weniger fehleranfällige und problemlose Verwendung.

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();
  }
}
Thuy Trinh
quelle
1

Für den Timing-Betrieb sollten Sie Handler verwenden .

Wenn Sie einen Hintergrunddienst ausführen müssen, ist der AlarmManager der richtige Weg.

robsf
quelle
0

In diesem Beispiel wird die in Kotlin zerstörte Timer-Einheit gestartet

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

    }

Brechen Sie die Zeitaufgabe in onDestroy () ab

timerTask.cancel()
Kshitiz Mishra
quelle