Jak ustawić minutnik w Androidzie

172

Jaki jest właściwy sposób ustawienia licznika czasu w systemie Android, aby rozpocząć zadanie (funkcja, którą utworzę, która nie zmienia interfejsu użytkownika)? Użyj tego w sposób Java: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html

Czy jest lepszy sposób na Androida (program obsługi Androida)?

n179911
źródło

Odpowiedzi:

143

Standardowy sposób używania timerów w Javie za pośrednictwem java.util.Timer i java.util.TimerTask działa dobrze w systemie Android, ale należy pamiętać, że ta metoda tworzy nowy wątek.

Możesz rozważyć użycie bardzo wygodnej klasy Handler (android.os.Handler) i wysyłać komunikaty do programu obsługi za pośrednictwem sendMessageAtTime(android.os.Message, long)lub sendMessageDelayed(android.os.Message, long). Po otrzymaniu wiadomości możesz uruchomić żądane zadania. Drugą opcją byłoby utworzenie obiektu Runnable i zaplanowanie go za pomocą funkcji Handler postAtTime(java.lang.Runnable, long)lub postDelayed(java.lang.Runnable, long).

MannyNS
źródło
10
To jest zły sposób robienia rzeczy w Androidzie. W systemie Android chcesz używać Menedżera alarmów (developer.android.com/reference/android/app/AlarmManager.html) do wykonywania zadań w odległej przyszłości.
Kurtis Nusbaum
9
@Kurtis Nusbaum Pytanie nie mówi, jak daleko w przyszłości jest to zadanie.
Christopher Perry,
67
@KurtisNusbaum To niekoniecznie prawda, zależy to od kontekstu. Dokumentacja na AlarmManager mówi: „Uwaga: Menedżer alarmów jest przeznaczony do przypadków, w których chcesz, aby kod aplikacji był uruchamiany o określonej godzinie, nawet jeśli aplikacja nie jest aktualnie uruchomiona. W przypadku normalnych operacji czasowych (takty, przekroczenia czasu itp.) korzystanie z programu Handler jest łatwiejsze i bardziej wydajne ”.
Christopher Perry,
5
@Scienceprodigy Ach, rozumiem. Słusznie.
Kurtis Nusbaum
10
użycie metody Handler do planowania zadania jest niezawodne tylko wtedy, gdy aplikacja uzyskała funkcję WakeLock i dzięki temu masz pewność, że telefon nie przejdzie w stan uśpienia. Jeśli telefon przejdzie w stan uśpienia, funkcje sendMessageDelayed oraz sendMessageAtTime nie będą działać. Stąd w tym scenariuszu AlarmManager byłby niezawodnym wyborem.
crazyaboutliv
159

tak, można użyć timera javy , ale ponieważ pytanie dotyczy lepszego sposobu (dla telefonów komórkowych). Co jest wyjaśnione tutaj .


Ze względu na StackOverflow:

Ponieważ Timer tworzy nowy wątek, można go uznać za ciężki,

jeśli wszystko, czego potrzebujesz, to oddzwonienie podczas działania działania, Handler może być używany w połączeniu z

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

lub wiadomość

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

na marginesie, to podejście można zastosować, jeśli chcesz uruchomić fragment kodu w wątku interfejsu użytkownika z innego wątku.

Jeśli potrzebujesz oddzwonienia, nawet jeśli Twoja aktywność nie jest uruchomiona, możesz użyć AlarmManager

Samuel
źródło
1
O tak, wygooglowałem dokładnie tę odpowiedź. Odbierz mój głos za przydatnym linkiem.
ulidtko
1
zaktualizował link, porozmawiaj o tym, że Google ma problemy z utrzymaniem linków.
Samuel,
1
Ten artykuł z 2007 roku - nie mówię, że jest zły, ale zawsze jestem podejrzliwy w stosunku do artykułu mobilnego, jeśli jest starszy niż 3 lata. Wszystko szybko się zmienia.
StackOverflowed
1
byłoby bardziej jak StackOverflow, gdybyś mógł zacytować tutaj główne punkty swojego linku w swojej odpowiedzi.
n611x007
1
@naxa, moje dwa centy, aby ta odpowiedź bardziej przypominała StackOverflow.
Samuel,
131

Jak widziałem, java.util.Timer jest najczęściej używany do implementacji timera.

W przypadku powtarzającego się zadania:

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

W przypadku pojedynczego uruchomienia zadania:

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


zadanie będące metodą do wykonania
po czasie do wykonania początkowego
( interwał czas na powtórzenie wykonania)

Thizzer
źródło
9
Dodam tylko, że czas jest w milisekundach
Uri
2
android dev docs for scheduleAtFixedRate
n611x007
1
taskmoże być instancją Twojej klasy, która dziedziczy po java.util.TimerTask i nadpisuje void run().
n611x007
2
Tak wiele głosów poparcia. Mógłbyś do tego. Ale @Samuel opisuje lepszy sposób. Zobacz jego link „Co jest tutaj wyjaśnione”, aby dowiedzieć się, dlaczego. Nie można również zaktualizować interfejsu użytkownika z wątku timera! I zobacz te inne odpowiedzi oparte na Handler w innych wątkach: (proste) stackoverflow.com/a/6702767/199364 lub (pokazuje różne alternatywy) stackoverflow.com/a/4598737/199364
ToolmakerSteve
@quemeful, ponieważ nie zawsze chodzi o wygodę, chodzi o jakość kodu i wydajność. Ten sposób
wymaga
33

Mam nadzieję, że ta jest pomocna i może wymagać mniej wysiłku w implementacji, klasy Android CountDownTimer

na przykład

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

      public void onFinish() {
          mTextField.setText("done!");
      }  
}.start();
Gaurav Adurkar
źródło
1
Jest to najłatwiejsze i uderza prosto w głowę, aby odliczać tak jak czas rozpoczęcia odtwarzania wideo
Vijay Kumar Kanta
17

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

lub

Metoda 2 ::

Zaprogramuj minutnik

Dodaj nową zmienną int o nazwie time. Ustaw na 0. Dodaj następujący kod do funkcji onCreate w pliku 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);

Przejdź do metody uruchamiania i dodaj następujący kod.

//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
źródło
11

To jest sytuacyjne.

Dokumentacja systemu Android sugeruje, że powinieneś użyć AlarmManagera do zarejestrowania intencji, która zostanie uruchomiona w określonym czasie, jeśli Twoja aplikacja może nie być uruchomiona.

W przeciwnym razie powinieneś użyć Handler.

Uwaga: Menedżer alarmów jest przeznaczony dla przypadków, w których chcesz, aby kod aplikacji był uruchamiany w określonym czasie, nawet jeśli aplikacja nie jest aktualnie uruchomiona. W przypadku normalnych operacji związanych z synchronizacją (takty, przekroczenia limitu czasu itp.) Łatwiejsze i znacznie wydajniejsze jest użycie programu Handler.

Timothy Lee Russell
źródło
11

Zaczynamy .. Będziemy potrzebować dwóch klas. Wysyłam kod, który zmienia profil mobilnego audio co 5 sekund (5000 mili sekund) ...

Nasza pierwsza klasa

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

}

Nasza 2 klasa

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
źródło
5

Jestem początkującym użytkownikiem Androida, ale oto klasa timera, którą utworzyłem na podstawie powyższych odpowiedzi. Działa w mojej aplikacji, ale wszelkie sugestie są mile widziane.

Przykład użycia:

...{
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
źródło
3

Używam programu obsługi i można go uruchomić, aby utworzyć licznik czasu. Otaczam to w abstrakcyjną klasę. Po prostu wyprowadź / zaimplementuj to i jesteś gotowy:

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

Zauważ, że handler.postDelayedjest wywoływana przed kodem, który ma zostać wykonany - spowoduje to, że licznik czasu będzie bardziej zamknięty zgodnie z oczekiwaniami. Jednak w przypadkach, gdy licznik czasu działa zbyt często, a zadanie ( onTimer()) jest długie - mogą się pokrywać. Jeśli chcesz rozpocząć liczenie intervalMSpo wykonaniu zadania, przesuń onTimer()połączenie o linię powyżej.

elcuco
źródło
2

Uważam, że sposobem na to na Androidzie jest to, że do działania potrzebna jest usługa w tle. W tej aplikacji działającej w tle utwórz licznik czasu. Gdy stoper „tyka” (ustaw interwał czasu oczekiwania), uruchom aktywność, którą chcesz rozpocząć.

http://developer.android.com/guide/topics/fundamentals.html (<- ten artykuł wyjaśnia związek między działaniami, usługami, intencjami i innymi podstawowymi podstawami programowania Androida)

Crowe T. Robot
źródło
1

Kiedyś używałem ( Timer, TimerTask), a także Handlerokresowo uruchamiałem (czasochłonne) zadania. Teraz przerzuciłem całość na RxJava. RxJava zapewnia Observable.timerprostszą, mniej podatną na błędy i bezproblemową obsługę .

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
źródło
1

Do operacji synchronizacji należy używać Handler .

Jeśli potrzebujesz uruchomić usługę w tle, najlepszym rozwiązaniem jest AlarmManager.

robsf
źródło
0

ten przykład uruchamia jednostkę czasową zniszczoną w Kotlinie

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

    }

Anuluj zadanie czasowe w onDestroy ()

timerTask.cancel()
Kshitiz Mishra
źródło