Таймер Android?Как? - PullRequest
       17

Таймер Android?Как?

305 голосов
/ 04 января 2011

Может ли кто-нибудь привести простой пример обновления текстового поля каждую секунду или около того?

Я хочу создать летающий шар и мне нужно вычислять / обновлять координаты шара каждую секунду, поэтому мне нужно что-то вродетаймер.

Я ничего не получаю от здесь .

Ответы [ 18 ]

442 голосов
/ 05 января 2011

хорошо, так как это еще не выяснено, есть 3 простых способа справиться с этим.Ниже приведен пример, показывающий все 3, а внизу - пример, показывающий, какой метод я считаю предпочтительным.Также не забывайте очищать свои задачи в onPause, сохраняя состояние при необходимости.


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


главное помнить, что пользовательский интерфейс можно изменять только из основного потока пользовательского интерфейса, поэтому используйте обработчик или activity.runOnUIThread(Runnable r);

Вот то, что я считаю предпочтительным методом.


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

}


81 голосов
/ 04 января 2011

Это просто! Вы создаете новый таймер.

Timer timer = new Timer();

Затем вы продлеваете задачу таймера

class UpdateBallTask extends TimerTask {
   Ball myBall;

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

А затем добавить новое задание в таймер с некоторым интервалом обновления

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

Отказ от ответственности: это не идеальное решение. Это решение с использованием класса Timer (по запросу OP). В Android SDK рекомендуется использовать класс Handler (в принятом ответе есть пример).

62 голосов
/ 24 сентября 2012

Если вам также нужно запустить код в потоке пользовательского интерфейса (а не в потоке таймера), загляните в блог: 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

    }
};
}
34 голосов
/ 25 августа 2014

Если вы просто хотите запланировать обратный отсчет до определенного времени в будущем с регулярными уведомлениями о интервалах по пути, вы можете использовать класс CountDownTimer , который доступен с уровня API 1.

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

    public void onFinish() {
        editText.setText("Done");
    }
}.start();
21 голосов
/ 23 июня 2016

Это простой код для таймера:

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

        System.out.println("1");
    }
};
timer.scheduleAtFixedRate(t,1000,1000);
10 голосов
/ 27 декабря 2015

Я думаю, что вы можете сделать это в Rx, например:

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

И отмените это как:

timerSubscribe.unsubscribe();

Таймер Rx http://reactivex.io/documentation/operators/timer.html

8 голосов
/ 10 марта 2017

Поскольку этот вопрос по-прежнему привлекает множество пользователей из поиска в Google (о таймере Android), я хотел бы вставить две свои монеты.

Прежде всего, класс Timer устареет в Java 9 (прочитайте принятый ответ) .

Официальный способ предлагает использовать ScheduledThreadPoolExecutor , который является более эффективным и многофункциональным, что может дополнительно планировать выполнение команд после заданной задержки или периодическое выполнение. Кроме того, он обеспечивает дополнительную гибкость и возможности ThreadPoolExecutor.

Вот пример использования простых функций.

  1. Создать службу исполнителя:

    final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
    
  2. Только расписание, которое вы запускаете:

    final Future<?> future = SCHEDULER.schedule(Runnable task, long delay,TimeUnit unit);
    
  3. Теперь вы можете использовать future, чтобы отменить задание или проверить, выполнено ли оно, например:

    future.isDone();
    

Надеюсь, вы найдете это полезным для создания задач в Android.

Полный пример:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Future<?> sampleFutureTimer = scheduler.schedule(new Runnable(), 120, TimeUnit.SECONDS);
if (sampleFutureTimer.isDone()){
    // Do something which will save world.
}
5 голосов
/ 31 марта 2018

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

Сначала вам нужно настроить зависимость от Gradle, если вы еще этого не сделали:

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

(заменить x и y с номер текущей версии )

Так как у нас есть простая, НЕПОВТОРАЯ ЗАДАЧА , мы можем использовать Completable объект:

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

Для ПОВТОРЯЯ ЗАДАНИЕ , вы можете использовать Observable аналогичным образом:

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

Schedulers.computation() гарантирует, что наш таймер работает в фоновом потокеи .observeOn(AndroidSchedulers.mainThread()) означает, что код, который мы запускаем после завершения таймера, будет выполнен в главном потоке.

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

2 голосов
/ 30 мая 2013

Он - более простое решение, прекрасно работает в моем приложении.

  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 голосов
/ 04 января 2011

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

Лучший способ - использовать обработчик, использующий postDelayed для запуска Runnable после задержки (каждый запуск планирует следующий);очистите обратный вызов с помощью removeCallbacks.

Вы уже искали правильное место, поэтому посмотрите на него еще раз, возможно, поясните, почему этот пример кода не тот, который вам нужен.(См. Также ту же статью на Обновление интерфейса от таймера ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...