Як встановити таймер в android


172

Який правильний спосіб встановити таймер в android для того, щоб почати завдання (функція, яку я створюю, яка не змінює інтерфейс користувача)? Скористайтеся цим способом на Java: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html

Або є кращий спосіб в андроїді (обробник андроїда)?

Відповіді:


143

Стандартний спосіб використання Java через таймери через java.util.Timer та java.util.TimerTask відмінно працює в Android, але ви повинні знати, що цей метод створює нову нитку.

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


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:

Оскільки Таймер створює нову нитку, це може вважатися важким,

якщо все, що вам потрібно, це отримати зворотний дзвінок, поки активність запущена, обробник може використовуватися спільно з a

Виконується :

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
О так, я гуглив саме цю відповідь. Візьміть мою нагороду за корисне посилання.
улідко

1
оновлено посилання, поговоріть про google, що мають проблеми з підтримкою посилань.
Самуїл

1
Ця стаття від 2007 року - не кажучи, що вона неправильна, але мені завжди подобається мобільна стаття, якщо вона старше 3 років. Речі змінюються досить швидко.
StackOverflowed

1
це було б більше схожим на StackOverflow, якби ви могли процитувати тут основні моменти вашої посилання.
n611x007

1
@naxa, два мої центи, щоб зробити цю відповідь більш схожою на StackOverflow.
Самуїл

131

Як я вже бачив, java.util.Timer найбільше використовується для впровадження таймера.

Для повторюваного завдання:

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

Для одного виконання завдання:

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


завдання - метод, який слід виконати
після часу первинного виконання
( інтервал часу для повторення виконання)


9
Я просто додам, що час в мілісекундах
Урі

2
Android Dev Документи для 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
Це найпростіше, і це удари прямо по голові для простого відліку, як час початку відео відтворення
Vijay Kumar Kanta

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 з ім'ям часу. Встановіть його 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);

Перейдіть до методу запуску та додайте наступний код.

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

});

11

Це ситуативно.

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

В іншому випадку вам слід скористатися 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);
    }

}

Наш 2-й клас

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

3

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

 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()виклик на рядок вище.


2

Я вважаю, що спосіб зробити це на андроїді полягає в тому, що для роботи вам потрібна фонова служба. У цьому фоновому додатку створіть таймер. Коли таймер "тикне" (встановіть інтервал, скільки часу ви хочете чекати), запустіть свою діяльність, яку ви хочете почати.

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 - це шлях.


0

у цьому прикладі запустіть таймер unitl, зруйнований у Котліні

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()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.