Как установить таймер в Android

172

Как правильно установить таймер в Android для запуска задачи (функция, которую я создаю, которая не меняет пользовательский интерфейс)? Используйте этот способ Java: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html

Или есть лучший способ в Android (обработчик Android)?

n179911
источник

Ответы:

143

Стандартный Java-способ использования таймеров через java.util.Timer и java.util.TimerTask прекрасно работает в Android, но вы должны знать, что этот метод создает новый поток.

Вы можете рассмотреть возможность использования очень удобного класса Handler (android.os.Handler) и отправлять сообщения обработчику через sendMessageAtTime(android.os.Message, long)или sendMessageDelayed(android.os.Message, long). Получив сообщение, вы можете запускать нужные задачи. Второй вариант - создать объект Runnable и запланировать его с помощью функций обработчика postAtTime(java.lang.Runnable, long)или postDelayed(java.lang.Runnable, long).

MannyNS
источник
10
Это неправильный способ делать вещи в Android. В Android вы хотите использовать диспетчер тревог (developer.android.com/reference/android/app/AlarmManager.html) для выполнения задач в далеком будущем.
Куртис Нусбаум
9
@ Kurtis Nusbaum Вопрос не говорит, как далеко в будущем задача.
Кристофер Перри
67
@KurtisNusbaum Это не обязательно так, это зависит от контекста. Документы на AlarmManager говорят: «Примечание. Диспетчер тревог предназначен для случаев, когда вы хотите, чтобы код вашего приложения запускался в определенное время, даже если ваше приложение в данный момент не запущено. Для обычных операций синхронизации (тики, тайм-ауты и т. Д.) проще и намного эффективнее использовать Handler. "
Кристофер Перри
5
@ Scienceprodigy Ах, понятно. Справедливо.
Куртис Нусбаум
10
Использование метода Handler для планирования задачи надежно только в том случае, если приложение получило wakeLock, и, следовательно, вы уверены, что телефон не перейдет в спящее состояние. Если телефон переходит в состояние сна, то sendMessageDelayed и sendMessageAtTime работать не будут. Следовательно в этом сценарии AlarmManager будет надежным выбором.
crazyaboutliv
159

да, можно использовать таймер Java , но так как вопрос требует лучшего способа (для мобильных устройств). Что объясняется здесь .


Ради StackOverflow:

Так как Timer создает новый поток, его можно считать тяжелым,

если все, что вам нужно, - это перезвонить во время выполнения действия, то обработчик можно использовать вместе с

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

или сообщение

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

В дополнение к этому, этот подход можно использовать, если вы хотите запустить фрагмент кода в потоке пользовательского интерфейса из другого потока.

если вам нужно перезвонить, даже если ваша активность не работает, вы можете использовать AlarmManager

Самуил
источник
1
О да, я гуглил именно этот ответ. Возьми мой upvote за полезную ссылку.
Улидько
1
обновил ссылку, поговорим о том, что у Google возникли проблемы с сохранением ссылок.
Самуил
1
Эта статья за 2007 год - я не говорю, что это неправильно, но я всегда с подозрением отношусь к мобильной статье, если она старше 3 лет. Все меняется довольно быстро.
Переполнение
1
было бы больше похоже на StackOverflow, если бы вы могли указать основные моменты своей ссылки здесь в своем ответе.
n611x007
1
@naxa, мои два цента, чтобы сделать этот ответ больше похожим на StackOverflow.
Самуил
131

Как я видел, java.util.Timer наиболее часто используется для реализации таймера.

Для повторяющейся задачи:

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

Для одного запуска задачи:

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


задача - метод, который должен быть выполнен
после времени начального выполнения
( интервал времени для повторения выполнения)

Thizzer
источник
9
Я просто добавлю, что время в миллисекундах
Uri
2
документы для разработчиков Android для scheduleAtFixedRate
n611x007
1
taskможет быть экземпляром вашего класса, который наследуется от java.util.TimerTask и переопределяет void run().
n611x007
2
Так много голосов. Вы могли бы к этому. Но @Samuel описывает лучший способ. Посмотрите его ссылку "Что здесь объясняется", чтобы узнать почему. Кроме того, не может обновить пользовательский интерфейс из потока таймера! И посмотрите эти ответы на основе других обработчиков в других потоках: (простой) stackoverflow.com/a/6702767/199364 или (показывает различные альтернативы) stackoverflow.com/a/4598737/199364
ToolmakerSteve
@quemeful, потому что речь идет не всегда об удобстве, а о качестве и эффективности кода. Этот способ использует больше ресурсов, чем использование обработчика
inDepth
33

Я надеюсь, что это полезно и может потребовать меньше усилий для реализации, класс Android CountDownTimer

например

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

      public void onFinish() {
          mTextField.setText("done!");
      }  
}.start();
Гаурав Адуркар
источник
1
Это проще всего, и удары прямо в голову для простого обратного отсчета, как время начала воспроизведения видео
Виджай Кумар Канта
17

Наверное 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();

или

Способ 2 ::

Запрограммируйте таймер

Добавьте новую переменную int с именем time. Установите его в 0. Добавьте следующий код в функцию onCreate в 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);

Зайдите в метод run и добавьте следующий код.

//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
источник
11

Это ситуативный.

Документация по Android предполагает, что вы должны использовать AlarmManager для регистрации намерения, которое сработает в указанное время, если ваше приложение может не работать.

В противном случае вам следует использовать Handler.

Примечание. Диспетчер тревог предназначен для случаев, когда вы хотите, чтобы код вашего приложения запускался в определенное время, даже если ваше приложение в данный момент не запущено. Для обычных операций синхронизации (тики, тайм-ауты и т. Д.) Проще и намного эффективнее использовать Handler.

Тимоти Ли Рассел
источник
11

Здесь мы идем .. Нам понадобятся два класса. Я публикую код, который меняет профиль мобильного аудио через каждые 5 секунд (5000 миль) ...

Наш 1-й класс

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

}

Наш второй класс

public class CustomTimerTask extends TimerTask {

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

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

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

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

    }

}
Ризван Сохаиб
источник
5

Я новичок в Android, но вот класс таймера, который я создал на основе ответов выше. Это работает для моего приложения, но я приветствую любые предложения.

Пример использования:

...{
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
источник
3

Я использую обработчик и runnable для создания таймера. Я оборачиваю это в абстрактный класс. Просто извлеките / внедрите его, и все готово:

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

Обратите внимание, что handler.postDelayedвызывается перед кодом, который должен быть выполнен - ​​это сделает таймер более закрытым, как и ожидалось. Однако в тех случаях, когда таймер часто запускается, а задача ( onTimer()) длинная, возможны совпадения. Если вы хотите начать считать intervalMSпосле выполнения задачи, переместите onTimer()вызов на строку выше.

elcuco
источник
2

Я считаю, что способ сделать это на Android является то, что вам нужен фоновый сервис для запуска. В этом фоновом приложении создайте таймер. Когда таймер «тикает» (установите интервал времени, в течение которого вы хотите ждать), запустите свою деятельность, которую вы хотите начать.

http://developer.android.com/guide/topics/fundamentals.html (<- эта статья объясняет взаимосвязь между действиями, услугами, намерениями и другими основными принципами разработки Android)

Кроу Т. Робот
источник
1

Раньше я использовал ( Timer, TimerTask), а также Handlerпериодически запускать (трудоемкие) задачи. Теперь я полностью перешел на RxJava. RxJava предоставляет Observable.timerболее простой, менее подверженный ошибкам, беспроблемный в использовании.

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

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

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

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

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

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

    // Don't kick off tasks when the app gets invisible.
    timerSubscription.unsubscribe();
  }
}
Туи триньх
источник
1

Для временной операции вы должны использовать Handler .

Если вам нужно запустить фоновый сервис, AlarmManager - это то, что вам нужно.

robsf
источник
0

этот пример запуска таймера unitl уничтожен в Kotlin

private lateinit var timerTask: TimerTask

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

    }

Отмените задание таймера в onDestroy ()

timerTask.cancel()
Кшитиз Мишра
источник