Чи може хтось навести простий приклад оновлення текстового поля щосекунди чи так?
Я хочу скласти літаючий кулю і мені потрібно обчислювати / оновлювати координати кулі щосекунди, тому мені потрібен якийсь таймер.
Я нічого не беру звідси .
Чи може хтось навести простий приклад оновлення текстового поля щосекунди чи так?
Я хочу скласти літаючий кулю і мені потрібно обчислювати / оновлювати координати кулі щосекунди, тому мені потрібен якийсь таймер.
Я нічого не беру звідси .
Відповіді:
нормально, оскільки це не очищено, але є 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");
}
}
Це просто! Ви створюєте новий таймер.
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 (є приклад у прийнятій відповіді).
Якщо вам також потрібно запустити свій код на потоці інтерфейсу (а не на потоці таймера), подивіться у блозі: 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
}
};
}
Якщо ви просто хочете запланувати зворотний відлік часу на майбутнє з регулярними повідомленнями з інтервалом по дорозі, ви можете використовувати клас 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();
SS:MiMi
? Спасибі
Це простий код для таймера:
Timer timer = new Timer();
TimerTask t = new TimerTask() {
@Override
public void run() {
System.out.println("1");
}
};
timer.scheduleAtFixedRate(t,1000,1000);
Я думаю, що ти можеш це зробити так, як:
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
Оскільки це питання все ще приваблює багато користувачів із пошуку Google (про таймер Android), я хотів би вставити дві монети.
Перш за все, клас Timer буде застарілим у Java 9 (прочитайте прийняту відповідь) .
Чиновник запропонував спосіб полягає у використанні ScheduledThreadPoolExecutor , який є більш ефективним і показує , що багаті можуть додатково команди розкладу для запуску після даної затримки, або періодично виконувати. Плюс це дає додаткову гнучкість та можливості ThreadPoolExecutor.
Ось приклад використання простих функціональних можливостей.
Створіть службу виконавця:
final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
Просто розкладіть програму:
final Future<?> future = SCHEDULER.schedule(Runnable task, long delay,TimeUnit unit);
Тепер ви можете 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.
}
Я здивований, що немає відповіді, яка б згадувала рішення з 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())
означає, що код, який ми виконуємо після закінчення таймеру, буде виконано на основному потоці.
Щоб уникнути небажаних витоків пам’яті, слід забезпечити скасування підписки, коли діяльність / фрагмент знищені.
Subscription
повернений .subscribe()
метод методом у змінній, а потім зателефонуйте, subscription.unsubscribe()
коли ви хочете зупинити таймер.
Він є більш простим рішенням, прекрасно працює в моєму додатку.
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;
}
}
}
Ви хочете, щоб ваші оновлення інтерфейсу відбувалися у вже існуючому потоці інтерфейсу користувача.
Найкращий спосіб - використовувати обробник, який використовує postDelayed для запуску Runnable після затримки (кожен графік виконання наступний); очистити зворотний дзвінок за допомогою RemoveCallbacks.
Ви вже шукаєте в потрібному місці, тому подивіться на це ще раз, можливо, уточніть, чому цей зразок коду - це не те, що потрібно. (Дивіться також ідентичну статтю в розділі Оновлення інтерфейсу користувача з таймера ).
Ось простий надійний спосіб ...
Введіть такий код у свою діяльність, і метод галочки () буде викликатися щосекунди в потоці інтерфейсу користувача, поки ваша активність перебуває у стані "відновлення". Звичайно, ви можете змінити метод галочки (), щоб робити те, що хочете, або називати його більш-менш часто.
@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" необхідний, щоб уникнути одночасного запуску двох таймерів, якщо ваша діяльність призупинена і відновлена протягом періоду галочки.
_h0
підхід, а НЕ removeCallbacks
в onPause
, як всі інші?
Ви також можете використовувати для нього аніматора:
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();
Вам потрібно створити потік для обробки циклу оновлення та використовувати його для оновлення textarea. Хоча хитра частина полягає в тому, що тільки головний потік може фактично змінювати інтерфейс користувача, тому нитка циклу оновлення повинна сигналізувати головний потік для оновлення. Це робиться за допомогою обробника.
Перевірте це посилання: http://developer.android.com/guide/topics/ui/dialogs.html# Клацніть на розділі під назвою "Приклад ProgressDialog з другою ниткою". Це приклад того, що саме потрібно зробити, за винятком діалогового вікна прогресу замість текстового поля.
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 ");
}
Якщо когось цікавить, я почав займатися створенням стандартного об'єкта для запуску на потоці інтерфейсу користувача. Здається, працює добре. Коментарі вітаються. Я хотів би, щоб це було доступне в дизайнері макетів як компонент для перетягування на діяльність. Не можу повірити, що щось подібне ще не існує.
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();
}
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"/>
Якщо у вас вже є дельта-час.
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();
}
}
}
Я відібрав абстрактний таймер і зробив його окремим класом:
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++;
}
});
}
...
}
Я сподіваюся, що це допомагає 😊👌
Я використовую такий спосіб:
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();
це простий спосіб вирішити цю проблему.
Для тих, хто не може покластися на хронометр , я зробив клас корисності з однієї з пропозицій:
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();