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


325

Чи може хтось навести простий приклад оновлення текстового поля щосекунди чи так?

Я хочу скласти літаючий кулю і мені потрібно обчислювати / оновлювати координати кулі щосекунди, тому мені потрібен якийсь таймер.

Я нічого не беру звідси .


14

Відповіді:


463

нормально, оскільки це не очищено, але є 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");
    }

}



1
@ Dave.B, дякую за чудовий приклад. Чи є якісь переваги / недоліки використання одного методу проти інших, які ви окреслили?
Гаутам

2
@Gautam Я вважаю, що всі вищевказані методи виконують приблизно те саме. Я особисто віддаю перевагу описаному вище методу обробника із запуском Runnable та h2 Handler, оскільки це той, який призначений веб-сайтом для розробників android, і, на мою думку, також найелегантніший.
Дейв.B

6
Було б добре, щоб ваш бажаний метод був відокремлений від решти коду. Можливо, у вас може бути один приклад, який показує ваш бажаний спосіб, а інший - альтернативи. Маючи всі три методи разом, це важче зрозуміти, що відбувається (особливо для андроїд-новачка, як я). Напевно, хоч занадто просимо :)
Джессі Олдрідж

4
@JesseAldridge Гарна ідея. Я пішов вперед і додав код лише бажаним методом.
Дейв.B

1
@bluesm Я чесно просто не думав про це, але так, це буде добре.
Дейв.B

84

Це просто! Ви створюєте новий таймер.

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

Відмова від відповідальності: Це не ідеальне рішення. Це рішення, використовуючи клас Таймер (на запитання ОП). В Android SDK рекомендується використовувати клас Handler (є приклад у прийнятій відповіді).


1
якщо ви прочитаєте публікацію вище, побачите, чому це не ідеальне рішення
Дейв.B

2
Звичайно. ОП хотіла це зробити з TimerTask, який я не рекомендую використовувати в грі.
вигадка

3
Так? ОП не вказала, як вони цього хочуть. Вони посилалися на статтю, яка використовувала TimerTask, але не вимагали, щоб це було зроблено саме так.
ToolmakerSteve

1
Допомагав багато, Дякую @fiction
Naveed Ahmad

1
чудова відповідь простий у слідуванні.
JMASTER B

64

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

    }
};
}

Для повноти ви можете, можливо, згадати, що потрібно зробити, щоб зупинити таймер, і, можливо, перезапустити його. (Я виявив необхідну інформацію тут: stackoverflow.com/questions/11550561 / ... )
RenniePet

3
Чи є якась причина, що ви не можете просто викликати runOnUIThread безпосередньо з методу запуску TimerTask? Здається, добре працює і знімає інший рівень гніздування.
RichieHH

Звичайно, це лише дидактичний метод зрозуміти всі кроки. Я пропоную цьому стандарту мати читабельний код.
Meir Gerenstadt

41

Якщо ви просто хочете запланувати зворотний відлік часу на майбутнє з регулярними повідомленнями з інтервалом по дорозі, ви можете використовувати клас 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();

2
CountDownTimer має сенс лише в тому випадку, якщо ви знаєте, що хочете, щоб він пішов після кількох страт. Це не типовий, ні особливо гнучкий підхід. Більш поширеним є таймер, який повторюється назавжди (який ви скасовуєте, коли це більше не потрібно), або обробник, який запускається один раз, а потім запускається знову, якщо знову знадобиться. Дивіться інші відповіді.
ToolmakerSteve

1
Ви абсолютно праві. Від назви класу він одноразово відраховує тикер таймера до кінця, і, звичайно, він використовує Handler у своїй реалізації.
Ахмед Гегазі

Як показати також мілісекунди? У форматі SS:MiMi? Спасибі
Рухір Баронія

26

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

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

        System.out.println("1");
    }
};
timer.scheduleAtFixedRate(t,1000,1000);

12

Я думаю, що ти можеш це зробити так, як:

 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


10

Оскільки це питання все ще приваблює багато користувачів із пошуку 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.
}

8

Я здивований, що немає відповіді, яка б згадувала рішення з 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.interval(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(tick -> {
            // called every 2 seconds, do something...
        }, throwable -> {
            // handle error
        });

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

Щоб уникнути небажаних витоків пам’яті, слід забезпечити скасування підписки, коли діяльність / фрагмент знищені.


4
Це найчистіший підхід!
Костянтин

як скасовує їх? тобто, коли користувач натискає кнопку [STOP] в інтерфейсі, і Completable скасовується перед виконанням.
Хтось десь

@SomeoneSomewhere Просто збережіть Subscriptionповернений .subscribe()метод методом у змінній, а потім зателефонуйте, subscription.unsubscribe()коли ви хочете зупинити таймер.
Місер

2

Він є більш простим рішенням, прекрасно працює в моєму додатку.

  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

Ви хочете, щоб ваші оновлення інтерфейсу відбувалися у вже існуючому потоці інтерфейсу користувача.

Найкращий спосіб - використовувати обробник, який використовує postDelayed для запуску Runnable після затримки (кожен графік виконання наступний); очистити зворотний дзвінок за допомогою RemoveCallbacks.

Ви вже шукаєте в потрібному місці, тому подивіться на це ще раз, можливо, уточніть, чому цей зразок коду - це не те, що потрібно. (Дивіться також ідентичну статтю в розділі Оновлення інтерфейсу користувача з таймера ).


На жаль, ваше посилання померло. Я не можу швидко знайти правильну статтю.
Лекенштейн


1

Ось простий надійний спосіб ...

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

@Override
public void onPause() {
    _handler = null;
    super.onPause();
}

private Handler _handler;

@Override
public void onResume() {
    super.onResume();
    _handler = new Handler();
    Runnable r = new Runnable() {
        public void run() {
            if (_handler == _h0) {
                tick();
                _handler.postDelayed(this, 1000);
            }
        }

        private final Handler _h0 = _handler;
    };
    r.run();
}

private void tick() {
    System.out.println("Tick " + System.currentTimeMillis());
}

Для тих, хто цікавиться, код "_h0 = _handler" необхідний, щоб уникнути одночасного запуску двох таймерів, якщо ваша діяльність призупинена і відновлена ​​протягом періоду галочки.


2
Чому цей незручний _h0підхід, а НЕ removeCallbacksв onPause, як всі інші?
ToolmakerSteve

1

Ви також можете використовувати для нього аніматора:

int secondsToRun = 999;

ValueAnimator timer = ValueAnimator.ofInt(secondsToRun);
timer.setDuration(secondsToRun * 1000).setInterpolator(new LinearInterpolator());
timer.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
    {
        @Override
        public void onAnimationUpdate(ValueAnimator animation)
        {
            int elapsedSeconds = (int) animation.getAnimatedValue();
            int minutes = elapsedSeconds / 60;
            int seconds = elapsedSeconds % 60;

            textView.setText(String.format("%d:%02d", minutes, seconds));
        }
    });
timer.start();

0

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

Перевірте це посилання: http://developer.android.com/guide/topics/ui/dialogs.html# Клацніть на розділі під назвою "Приклад ProgressDialog з другою ниткою". Це приклад того, що саме потрібно зробити, за винятком діалогового вікна прогресу замість текстового поля.


Не робіть цього. Існує простий клас таймерів, який робить це все за вас. І це питання взагалі не має нічого спільного з діалогами прогресу чи діалогами.
Фальмарі

Ви подивилися розділ посилання, яке я опублікував, чи ви просто бачили діалогове слово та припускаєте? Код там 100% релевантний. Також FYI, якщо ви використовуєте таймер, ви все ще створюєте нитку для обробки циклу оновлення. Вам все одно доведеться використовувати обробник, як описано у посиланні, яке я опублікував.
Нік

На жаль, пов’язана сторінка більше не містить розділу із згаданою назвою. При посиланні на код завжди слід включати фрагмент ключа безпосередньо у вашу відповідь.
ToolmakerSteve

0
void method(boolean u,int max)
{
    uu=u;
    maxi=max;
    if (uu==true)
    { 
        CountDownTimer uy = new CountDownTimer(maxi, 1000) 
  {
            public void onFinish()
            {
                text.setText("Finish"); 
            }

            @Override
            public void onTick(long l) {
                String currentTimeString=DateFormat.getTimeInstance().format(new Date());
                text.setText(currentTimeString);
            }
        }.start();
    }

    else{text.setText("Stop ");
}

2
Можливо, корисні будуть деякі відступи коду та пояснення коду.
Рауль Рене

0

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

package com.example.util.timer;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;

public class ActivityTimer {

    private Activity m_Activity;
    private boolean m_Enabled;
    private Timer m_Timer;
    private long m_Delay;
    private long m_Period;
    private ActivityTimerListener m_Listener;
    private ActivityTimer _self;
    private boolean m_FireOnce;

    public ActivityTimer() {
        m_Delay = 0;
        m_Period = 100;
        m_Listener = null;
        m_FireOnce = false;
        _self = this;
    }

    public boolean isEnabled() {
        return m_Enabled;
    }

    public void setEnabled(boolean enabled) {
        if (m_Enabled == enabled)
            return;

        // Disable any existing timer before we enable a new one
        Disable();

        if (enabled) {
            Enable();
        }
    }

    private void Enable() {
        if (m_Enabled)
            return;

        m_Enabled = true;

        m_Timer = new Timer();
        if (m_FireOnce) {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay);
        } else {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay, m_Period);
        }
    }

    private void Disable() {
        if (!m_Enabled)
            return;

        m_Enabled = false;

        if (m_Timer == null)
            return;

        m_Timer.cancel();
        m_Timer.purge();
        m_Timer = null;
    }

    private void OnTick() {
        if (m_Activity != null && m_Listener != null) {
            m_Activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    m_Listener.OnTimerTick(m_Activity, _self);
                }
            });
        }
        if (m_FireOnce)
            Disable();
    }

    public long getDelay() {
        return m_Delay;
    }

    public void setDelay(long delay) {
        m_Delay = delay;
    }

    public long getPeriod() {
        return m_Period;
    }

    public void setPeriod(long period) {
        if (m_Period == period)
            return;
        m_Period = period;
    }

    public Activity getActivity() {
        return m_Activity;
    }

    public void setActivity(Activity activity) {
        if (m_Activity == activity)
            return;
        m_Activity = activity;
    }

    public ActivityTimerListener getActionListener() {
        return m_Listener;
    }

    public void setActionListener(ActivityTimerListener listener) {
        m_Listener = listener;
    }

    public void start() {
        if (m_Enabled)
            return;
        Enable();
    }

    public boolean isFireOnlyOnce() {
        return m_FireOnce;
    }

    public void setFireOnlyOnce(boolean fireOnce) {
        m_FireOnce = fireOnce;
    }
}

У своїй діяльності у мене є цей старт:

@Override
protected void onStart() {
    super.onStart();

    m_Timer = new ActivityTimer();
    m_Timer.setFireOnlyOnce(true);
    m_Timer.setActivity(this);
    m_Timer.setActionListener(this);
    m_Timer.setDelay(3000);
    m_Timer.start();
}

1
чувак, що не так з ActivityTimerListener? Мій пакет ADT сказав, що такого класу немає.
Сорокін Андрій

0
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

 CheckBox optSingleShot;
 Button btnStart, btnCancel;
 TextView textCounter;

 Timer timer;
 MyTimerTask myTimerTask;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  optSingleShot = (CheckBox)findViewById(R.id.singleshot);
  btnStart = (Button)findViewById(R.id.start);
  btnCancel = (Button)findViewById(R.id.cancel);
  textCounter = (TextView)findViewById(R.id.counter);

  btnStart.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {

    if(timer != null){
     timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
     //singleshot delay 1000 ms
     timer.schedule(myTimerTask, 1000);
    }else{
     //delay 1000ms, repeat in 5000ms
     timer.schedule(myTimerTask, 1000, 5000);
    }
   }});

  btnCancel.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    if (timer!=null){
     timer.cancel();
     timer = null;
    }
   }
  });

 }

 class MyTimerTask extends TimerTask {

  @Override
  public void run() {
   Calendar calendar = Calendar.getInstance();
   SimpleDateFormat simpleDateFormat = 
     new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
   final String strDate = simpleDateFormat.format(calendar.getTime());

   runOnUiThread(new Runnable(){

    @Override
    public void run() {
     textCounter.setText(strDate);
    }});
  }

 }

}

.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:autoLink="web"
    android:text="http://android-er.blogspot.com/"
    android:textStyle="bold" />
<CheckBox 
    android:id="@+id/singleshot"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Single Shot"/>


Я бачу, що ви додали це через кілька років після оригінального запитання та відповідей. Будь ласка, додайте пояснення того, як ця відповідь порівнюється з іншими відповідями, які вже були там. Чому ви додали ще одну - яку перевагу / коли корисно / який недолік ви бачили в інших відповідях?
ToolmakerSteve

Я просто ділюсь кодом, який виконує ту саму роботу з іншим підходом. Але кожен раз, коли ви хочете оновити дані будь-якого перегляду. Ви повинні використовувати обробник для цього. тому що багато разів я помічаю, що використання таймерзадачі для оновлення подання не працює .. @ метод Dave.B є більш правильним, наскільки мені відомо.
Zar E Ahmer

0

Якщо у вас вже є дельта-час.

public class Timer {
    private float lastFrameChanged;
    private float frameDuration;
    private Runnable r;

    public Timer(float frameDuration, Runnable r) {
        this.frameDuration = frameDuration;
        this.lastFrameChanged = 0;
        this.r = r;
    }

    public void update(float dt) {
        lastFrameChanged += dt;

        if (lastFrameChanged > frameDuration) {
            lastFrameChanged = 0;
            r.run();
        }
    }
}

0

Я відібрав абстрактний таймер і зробив його окремим класом:

Timer.java

import android.os.Handler;

public class Timer {

    IAction action;
    Handler timerHandler = new Handler();
    int delayMS = 1000;

    public Timer(IAction action, int delayMS) {
        this.action = action;
        this.delayMS = delayMS;
    }

    public Timer(IAction action) {
        this(action, 1000);
    }

    public Timer() {
        this(null);
    }

    Runnable timerRunnable = new Runnable() {

        @Override
        public void run() {
            if (action != null)
                action.Task();
            timerHandler.postDelayed(this, delayMS);
        }
    };

    public void start() {
        timerHandler.postDelayed(timerRunnable, 0);
    }

    public void stop() {
        timerHandler.removeCallbacks(timerRunnable);
    }
}

І Витягнути основну дію з Timerкласу як

IAction.java

public interface IAction {
    void Task();
}

І я використовував це саме так:

MainActivity.java

public class MainActivity extends Activity implements IAction{
...
Timer timerClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
        ...
        timerClass = new Timer(this,1000);
        timerClass.start();
        ...
}
...
int i = 1;
@Override
public void Task() {
    runOnUiThread(new Runnable() {

        @Override
        public void run() {
            timer.setText(i + "");
            i++;
        }
    });
}
...
}

Я сподіваюся, що це допомагає 😊👌


0

Я використовую такий спосіб:

String[] array={
       "man","for","think"
}; int j;

потім нижче onCreate

TextView t = findViewById(R.id.textView);

    new CountDownTimer(5000,1000) {

        @Override
        public void onTick(long millisUntilFinished) {}

        @Override
        public void onFinish() {
            t.setText("I "+array[j] +" You");
            j++;
            if(j== array.length-1) j=0;
            start();
        }
    }.start();

це простий спосіб вирішити цю проблему.


0

Для тих, хто не може покластися на хронометр , я зробив клас корисності з однієї з пропозицій:

public class TimerTextHelper implements Runnable {
   private final Handler handler = new Handler();
   private final TextView textView;
   private volatile long startTime;
   private volatile long elapsedTime;

   public TimerTextHelper(TextView textView) {
       this.textView = textView;
   }

   @Override
   public void run() {
       long millis = System.currentTimeMillis() - startTime;
       int seconds = (int) (millis / 1000);
       int minutes = seconds / 60;
       seconds = seconds % 60;

       textView.setText(String.format("%d:%02d", minutes, seconds));

       if (elapsedTime == -1) {
           handler.postDelayed(this, 500);
       }
   }

   public void start() {
       this.startTime = System.currentTimeMillis();
       this.elapsedTime = -1;
       handler.post(this);
   }

   public void stop() {
       this.elapsedTime = System.currentTimeMillis() - startTime;
       handler.removeCallbacks(this);
   }

   public long getElapsedTime() {
       return elapsedTime;
   }
 }

використовувати .. просто робити:

 TimerTextHelper timerTextHelper = new TimerTextHelper(textView);
 timerTextHelper.start();

.....

 timerTextHelper.stop();
 long elapsedTime = timerTextHelper.getElapsedTime();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.