How to change the variable of a method in Runnable? - android

What I want to do is to change my run() method, such that it can receive different variables. I want to change player1life to something else, so that I can use customHandler.postDelayed(updateTimerThread, 0); on a different one, such as player2life.
What the code does, is, when a button is being pressed, a variable changes its value.
NOTE: I am an all most completely newbie in android development.
final android.os.Handler customHandler = new android.os.Handler();
final Runnable updateTimerThread = new Runnable()
{
public void run()
{ if(pressed) {
player1life--;
textView.setText(String.valueOf(player1life));
customHandler.postDelayed(this, 100);
}
}
};
leftButton1.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()){
case MotionEvent.ACTION_DOWN :
pressed = true;
customHandler.postDelayed(updateTimerThread, 0);
leftButton1.setImageResource(R.drawable.arrownewred);
winFunction();
break;
case MotionEvent.ACTION_UP :
pressed = false;
leftButton1.setImageResource(R.drawable.arrownew); break;
}
return true;
}
});

I smell an XY problem...
Why not create a different Runnable for handling player2life? In the on click handler, just do an if statement to check which players' life should you decrease!
if ... {
customHandler.postDelayed(runnableThatHandlesPlayer1Life, 0);
} else {
customHandler.postDelayed(runnableThatHandlesPlayer2Life, 0);
}
And the runnables can be declared this way:
final Runnable runnableThatHandlesPlayer1Life = new Runnable()
{
public void run()
{ if(pressed) {
player1life--;
textView.setText(String.valueOf(player1life));
customHandler.postDelayed(this, 100);
}
}
};
final Runnable runnableThatHandlesPlayer2Life = new Runnable()
{
public void run()
{ if(pressed) {
player2life--;
textView.setText(String.valueOf(player2life));
customHandler.postDelayed(this, 100);
}
}
};
But your code is kind of suspicious. From my understanding of your code, player1's life will decrease at a rate of 10/second when a button is pressed. It's strange.
It seems like that you're trying to create a timer thingy. Try this Timer class that I wrote. It should make things a bit easier:
import android.os.Handler;
public class Timer {
private Handler handler;
private boolean paused;
private int interval;
private Runnable task = new Runnable () {
#Override
public void run() {
if (!paused) {
runnable.run ();
Timer.this.handler.postDelayed (this, interval);
}
}
};
private Runnable runnable;
public int getInterval() {
return interval;
}
public void setInterval(int interval) {
this.interval = interval;
}
public void startTimer () {
paused = false;
handler.postDelayed (task, interval);
}
public void stopTimer () {
paused = true;
}
public Timer (Runnable runnable, int interval, boolean started) {
handler = new Handler ();
this.runnable = runnable;
this.interval = interval;
if (started)
startTimer ();
}
}

Is problem just getting past the need for final variables in the anonymous inner class? If so, you can use the "trick" of using a final array of length 1, and then updating the element of the array.
Here is a simple example:
public interface Incrementer {
void increment();
}
public class Foo {
private int bar = 0;
public int getBar() {
return bar;
}
public void increment() {
this.bar++;
System.out.println("value is now: " + bar);
}
}
public class Closure {
public static void main(String[] args) {
System.out.println("hello");
Foo foo1 = new Foo();
Foo foo2 = new Foo();
final Foo[] theFoo = {foo1};
Incrementer incrementer = new Incrementer() {
public void increment() {
theFoo[0].increment();
}
};
incrementer.increment();
incrementer.increment();
incrementer.increment();
theFoo[0] = foo2;
incrementer.increment();
incrementer.increment();
System.out.println("foo1 = " + foo1.getBar());
System.out.println("foo2 = " + foo2.getBar());
}
}

Related

Android studio update textview every 5 seconds

Hi my app needs a realtime data from database and I'm posting it on my TextView and I can't update the TextView as the database updates. I tried using Timer but its still the same.
Here is my code,
public void startTimer() {
//set a new Timer
timer = new Timer();
//initialize the TimerTask's job
initializeTimerTask();
timer.schedule(timerTask, 0, 5000);
}
private void stopTimerTask() {
//stop the timer, if it's not already null
if (timer != null) {
timer.cancel();
timer = null;
}
}
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
final AcceptCars Cars = (AcceptCars) getIntent().getSerializableExtra("cars");
renterLat.setText(Cars.renterLat);
renterLng.setText(Cars.renterLng);
Log.d(TAG,renterLat.getText().toString());
Log.d(TAG,renterLng.getText().toString());
}
});
}
};
}
And here is where I get the Cars.renterLat and Cars.renterLng,
public class AcceptCars implements Serializable {
#SerializedName("renterLat")
public String renterLat;
#SerializedName("renterLng")
public String renterLng;
}
This is the logic you should be following. I used a Handler instead of a Timer. Inside the run method you need to call your webservice and get the updated value from the db. Use runOnUiThread to update the value to the UI from a Thread.
See the code below,
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Handler taskHandler = new Handler();
taskHandler.postDelayed(myTask, 0);
}
private Runnable myTask = new Runnable(){
public void run() {
queryDb();
// repeat the task
taskHandler.postDelayed(this, 1000);
}
};
private void queryDb(){
new Thread(new Runnable() {
#Override
public void run() {
// call you webservice
String data = callWebservice();
// parse the data in to AcceptCars pojo class
AcceptCars Cars = parseData(data);
//update the UI
runOnUiThread(new Runnable() {
#Override
public void run() {
renterLat.setText(Cars.renterLat);
renterLng.setText(Cars.renterLng);
}
});
}
}).start();
}
You can even use countdown timer.
Here is the link https://developer.android.com/reference/android/os/CountDownTimer.html
TimerTasks are really hard to deal with IMO. You should use a Handler and call postDelayed to do something after a certain amount of time.
Alternatively, you can try out this timer class I wrote:
import android.os.Handler;
public class Timer {
private Handler handler;
private boolean paused;
private int interval;
private Runnable task = new Runnable () {
#Override
public void run() {
if (!paused) {
runnable.run ();
Timer.this.handler.postDelayed (this, interval);
}
}
};
private Runnable runnable;
public int getInterval() {
return interval;
}
public void setInterval(int interval) {
this.interval = interval;
}
public void startTimer () {
paused = false;
handler.postDelayed (task, interval);
}
public void stopTimer () {
paused = true;
}
public Timer (Runnable runnable, int interval, boolean started) {
handler = new Handler ();
this.runnable = runnable;
this.interval = interval;
if (started)
startTimer ();
}
}
It is really simple to use.
You can use it like this:
Timer timer = new Timer(new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
final AcceptCars Cars = (AcceptCars) getIntent().getSerializableExtra("cars");
renterLat.setText(Cars.renterLat);
renterLng.setText(Cars.renterLng);
Log.d(TAG,renterLat.getText().toString());
Log.d(TAG,renterLng.getText().toString());
}
}
}
}, 5000, true);

Android: Repeat a method and delay other method after x seconds using handle

I'm new to android and i have a problem
I used same code to repeat and delay method for two class. One class work fine but other not. I don't know why. This is my code
SpeedMeterFragment.java
public class SpeedMeterFragment extends Fragment {
....
public void speedMeterBefore() {
totalRxBytesBefore = TrafficStats.getTotalRxBytes();
Log.d("test", "Before: " + String.valueOf(totalRxBytesBefore));
}
public void speedMeterAfter() {
totalRxBytesAfter = TrafficStats.getTotalRxBytes();
Log.d("test", "After: " + String.valueOf(totalRxBytesAfter));
}
public void speedMeterDifference() {
totalRxBytesDifference = totalRxBytesAfter - totalRxBytesBefore;
tvTest.setText(String.valueOf(totalRxBytesDifference/1024) + " kb/s");
Log.d("test", "Difference: " + String.valueOf(totalRxBytesDifference));
}
public void speedMeter() {
handler = new Handler();
handler.post(runnable = new Runnable() {
#Override
public void run() {
speedMeterBefore();
final Handler handler1 = new Handler();
handler1.postDelayed(new Runnable() {
#Override
public void run() {
speedMeterAfter();
speedMeterDifference();
}
}, 1000);
handler.postDelayed(this, 1000);
}
});
}
}
and SaveDataUseage.java
public class SaveDataUseage extends BroadcastReceiver {
...
public void onReceive(Context context, Intent intent) {
...
savePreference();
}
public void savePreference() {
...
measureDataMB();
}
public void measureDataMBBefore() {
dataMBBefore = TrafficStats.getTotalRxBytes() / 1048576;
}
public void measureDataMBAfter() {
dataMBAfter = TrafficStats.getTotalRxBytes() / 1048576;
}
public void measureDataMBDifference() {
dataMBDifference = dataMBAfter - dataMBBefore;
}
public void measureDataMB() {
handler = new Handler();
handler.post(runnable = new Runnable() {
#Override
public void run() {
measureDataMBBefore();
final Handler handler1 = new Handler();
handler1.postDelayed(new Runnable() {
#Override
public void run() {
measureDataMBAfter();
measureDataMBDifference();
}
}, 1000);
handler.postDelayed(this, 1000);
}
});
}
}
SpeedMeterFragment work fine, but not SaveDataUseage
Anybody help me?
Sorry for my bad English :)
handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
//Your method called here
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(r, 1000);
this code will repeat method after every second
handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
//Your method called here
MyMethod(isCalledFromHandeler);
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(r, 1000);
use boolean argument isCalledFromHandeler to recognition the caller of method.
and then use
if(isCalledFromHandeler){
// Do Not call the Child Method
} else{
// Call the Child Method
}
Although its eight month old question, I also faced the similar problem and in solution I extended Handler class to AdvanceHandler with the postRepeated method.
Sample Usage
AdvanceHandler handler = new AdvanceHandler();
handler.postRepeated(new Runnable() {
#Override
public void run() {
//Your repeated task
}
}, 5000) //After every 5 seconds

postDelayed blocking ui thread

What I want: The user keeps the button clicked for 1900ms. If he picks his finger before 1900ms the phone stops vibrating. While if he keeps his finger on the button for more than 1900 sec, calculate() method runs.
I am using: postDelayed as I read it does not interfere with ui thread.
I was trying to check if 1900 sec has passed user has not picked his finger, even than calculate method runs.
Error Happening: If the user picks his finger before 1900 seconds or just he touches and immediately picks, the phone keeps vibrating. Although it should not happen as I am checking it with MotionEvent.ACTION_UP. Please help !!
int flag = 0;
int aborted_flag = 0;
#Override
public boolean onTouch(View v, MotionEvent event) {
Handler mHandler = new Handler();
if(event.getAction()==MotionEvent.ACTION_DOWN){
scanning();
t1 = System.currentTimeMillis();
vibrator.vibrate(1900);
mHandler.postDelayed(new Runnable() {
public void run() {
check();
}
}, 1901);
}
if(event.getAction()==MotionEvent.ACTION_UP){
if(flag == 0){
t2 = System.currentTimeMillis();
vibrator.cancel();
calculate();
aborted_flag = 1;
}
}
return true;
}
private void check() {
t2 = System.currentTimeMillis();
Log.e("Hello","Inside Check");
Log.e("Hello",""+aborted_flag);
vibrator.cancel();
if(aborted_flag==0){
calculate();
flag = 1;
}
}
private void scanning() {
textView.setText("Scanning");
}
private void calculate() {
Log.e("t2-t1 ", t2-t1+"");
if(t2-t1>=1900){
Random r = new Random();
int k = r.nextInt((5 - 0) + 1) + 0;
textView.setText(str[k]);
////////////animation library code/////////////
YoYo.with(Techniques.StandUp)
.duration(700)
.playOn(findViewById(R.id.text_view));
////////////////////////////////////////
changeBackgroundColor(k);
//textView.setTextColor(Color.parseColor("#00ff00"));
flag = 0;
}
else{
textView.setText("Aborted\n Try Again");
relativeLayout.setBackgroundResource(R.color.red);
}
}
public void changeBackgroundColor(final int k) {
runOnUiThread(new Runnable(){
public void run() {
switch(k){
case 0: relativeLayout.setBackgroundResource(R.color.blue);
break;
case 1: relativeLayout.setBackgroundResource(R.color.pink);
break;
case 2:;
case 3: relativeLayout.setBackgroundResource(R.color.green);
break;
default:relativeLayout.setBackgroundResource(R.color.yellow);
}
}
});
}
If you call postDelayed from the UI thread then your code will be executed on the UI thread.
To use a different thread create one:
Thread t = new Thread(new Runnable(){});
t.start();
You can create a HandlerThread and use it's looper to create a handler and then post stuff to it either post or postdelayed
public class myActivity extends Activity
{
private HandlerThread loaderThread;
private Handler loader;
#override
public void onResume()
{
super.onResume();
if (loaderThread == null)
{
loaderThread = new HandlerThread("MyActivitySeparateThread");
loaderThread.start();
loader = new Handler(loaderThread.getLooper());
}
}
#override
public void onDestroy()
{
//Stop and release handler
try {
loader.removeCallbacksAndMessages(null);
loader.dispose();
} finally {
loader = null;
}
//Stop and release Thread
try {
loaderThread.quit();
loaderThread.dispose();
} finally {
loaderThread = null;
}
super.onDestroy();
}
#Override
public boolean onTouch(View v, MotionEvent event)
{
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
scanning();
t1 = System.currentTimeMillis();
vibrator.vibrate(1900);
loader.postDelayed(new Runnable()
{
public void run()
{
check();
}
}, 1901);
break;
}
case MotionEvent.ACTION_UP:
{
if (flag == 0)
{
t2 = System.currentTimeMillis();
vibrator.cancel();
calculate();
aborted_flag = 1;
}
break;
}
}
return true;
}
}
Because in mHandler.postDelayed you call check() which calls calculate() which calls relativeLayout.setBackgroundResource(). UI can be changed only from UIThread.
Make function:
public void changeBackgroundColor(final int color) {
runOnUiThread(new Runnable(){
public void run() {
relativeLayout.setBackgroundResource(color);
}
});
}
And call it from your calculate() function.

Text View does not get update through handler

Actually, I have designed a seprate Timer class with handler for displaying minute and second on a textview. this works fine as I have debugged it and handler will reaise handle but the text view does not get updated pl help me in this regards.
I am tagging the code below for Timer Class.
thanks in advance.
public class Timer
{
private int _interval;
public int getInterval()
{
return _interval;
}
public void setInterval(int delay)
{
_interval = delay;
}
private Handler handler;
private Runnable _tickHandler;
private Runnable delegate;
private boolean ticking;
public boolean getIsTicking()
{
return ticking;
}
public Timer(int interval)
{
_interval = interval;
handler = new Handler();
}
public Timer(int interval, Runnable onTickHandler)
{
_interval = interval;
setOnTickHandler(onTickHandler);
handler = new Handler();
}
public void start(int interval, Runnable onTickHandler)
{
if (ticking) return;
_interval = interval;
setOnTickHandler(onTickHandler);
handler.postDelayed(delegate, _interval);
ticking = true;
}
public void start()
{
if (ticking) return;
handler.postDelayed(delegate, _interval);
ticking = true;
}
public void stop()
{
handler.removeCallbacks(delegate);
ticking = false;
}
public void setOnTickHandler(Runnable onTickHandler)
{
if (onTickHandler == null) return;
_tickHandler = onTickHandler;
delegate = new Runnable()
{
public void run()
{
if (_tickHandler == null) return;
_tickHandler.run();
handler.postDelayed(delegate, _interval);
}
}
;
}
}
and below is the code that I am using for updating Text View
Timer tmr = new Timer(100,new Runnable()
{
public void run()
{
long millis = System.currentTimeMillis() - mStartTime;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
lblDevOnOff.setText("");
lblDevOnOff.setText(String.format("%d:%02d", minutes,seconds));
}
}
);
tmr.start();
put this code in
handler or runOnUIThread() something like this
runOnUIThread(new Runnable(){
public void run(){
lblDevOnOff.setText("");
lblDevOnOff.setText(String.format("%d:%02d", minutes,seconds));
}
})
you should do this because anything related to UI should run on UI Thread only...
Yeah, this is from the Android Dev Guide:
Thus, there are simply two rules to Android's single thread model:
Do not block the UI thread
Do not access the Android UI toolkit from outside the UI thread

How to set timer in android?

Can someone give a simple example of updating a textfield every second or so?
I want to make a flying ball and need to calculate/update the ball coordinates every second, that's why I need some sort of a timer.
I don't get anything from here.
ok since this isn't cleared up yet there are 3 simple ways to handle this.
Below is an example showing all 3 and at the bottom is an example showing just the method I believe is preferable. Also remember to clean up your tasks in onPause, saving state if necessary.
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");
}
}
the main thing to remember is that the UI can only be modified from the main ui thread so use a handler or activity.runOnUIThread(Runnable r);
Here is what I consider to be the preferred method.
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");
}
}
It is simple!
You create new timer.
Timer timer = new Timer();
Then you extend the timer task
class UpdateBallTask extends TimerTask {
Ball myBall;
public void run() {
//calculate the new position of myBall
}
}
And then add the new task to the Timer with some update interval
final int FPS = 40;
TimerTask updateBall = new UpdateBallTask();
timer.scheduleAtFixedRate(updateBall, 0, 1000/FPS);
Disclaimer: This is not the ideal solution. This is solution using the Timer class (as asked by OP). In Android SDK, it is recommended to use the Handler class (there is example in the accepted answer).
If you also need to run your code on UI thread (and not on timer thread), take a look on the blog: 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
}
};
}
If one just want to schedule a countdown until a time in the future with regular notifications on intervals along the way, you can use the CountDownTimer class that is available since API level 1.
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
editText.setText("Seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
editText.setText("Done");
}
}.start();
This is some simple code for a timer:
Timer timer = new Timer();
TimerTask t = new TimerTask() {
#Override
public void run() {
System.out.println("1");
}
};
timer.scheduleAtFixedRate(t,1000,1000);
I think you can do it in Rx way like:
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
}
});
And cancel this like:
timerSubscribe.unsubscribe();
Rx Timer http://reactivex.io/documentation/operators/timer.html
I'm surprised that there is no answer that would mention solution with RxJava2. It is really simple and provides an easy way to setup timer in Android.
First you need to setup Gradle dependency, if you didn't do so already:
implementation "io.reactivex.rxjava2:rxjava:2.x.y"
(replace x and y with current version number)
Since we have just a simple, NON-REPEATING TASK, we can use Completable object:
Completable.timer(2, TimeUnit.SECONDS, Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(() -> {
// Timer finished, do something...
});
For REPEATING TASK, you can use Observable in a similar way:
Observable.interval(2, TimeUnit.SECONDS, Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(tick -> {
// called every 2 seconds, do something...
}, throwable -> {
// handle error
});
Schedulers.computation() ensures that our timer is running on background thread and .observeOn(AndroidSchedulers.mainThread()) means code we run after timer finishes will be done on main thread.
To avoid unwanted memory leaks, you should ensure to unsubscribe when Activity/Fragment is destroyed.
Because this question is still attracting a lot of users from google search(about Android timer) I would like to insert my two coins.
First of all, the Timer class will be deprecated in Java 9 (read the accepted answer).
The official suggested way is to use ScheduledThreadPoolExecutor which is more effective and features-rich that can additionally schedule commands to run after a given delay, or to execute periodically. Plus,it gives additional flexibility and capabilities of ThreadPoolExecutor.
Here is an example of using plain functionalities.
Create executor service:
final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
Just schedule you runnable:
final Future<?> future = SCHEDULER.schedule(Runnable task, long delay,TimeUnit unit);
You can now use future to cancel the task or check if it is done for example:
future.isDone();
Hope you will find this useful for creating a tasks in Android.
Complete example:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Future<?> sampleFutureTimer = scheduler.schedule(new Runnable(), 120, TimeUnit.SECONDS);
if (sampleFutureTimer.isDone()){
// Do something which will save world.
}
for whom wants to do this in kotlin:
val timer = fixedRateTimer(period = 1000L) {
val currentTime: Date = Calendar.getInstance().time
runOnUiThread {
tvFOO.text = currentTime.toString()
}
}
for stopping the timer you can use this:
timer.cancel()
this function has many other options, give it a try
import kotlin.concurrent.fixedRateTimer
val timer = fixedRateTimer("Tag", false, 1000, 2500) { /* Your code here */ }
Pretty simple with Kotlin
You want your UI updates to happen in the already-existent UI thread.
The best way is to use a Handler that uses postDelayed to run a Runnable after a delay (each run schedules the next); clear the callback with removeCallbacks.
You're already looking in the right place, so look at it again, perhaps clarify why that code sample isn't what you want. (See also the identical article at Updating the UI from a Timer).
He're is simplier solution, works fine in my app.
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;
}
}
}
You can also use an animator for it:
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();
For those who can't rely on Chronometer, I made a utility class out of one of the suggestions:
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;
}
}
to use..just do:
TimerTextHelper timerTextHelper = new TimerTextHelper(textView);
timerTextHelper.start();
.....
timerTextHelper.stop();
long elapsedTime = timerTextHelper.getElapsedTime();
enter code here
Thread th=new Thread(new Runnable() {
#Override
public void run() {
try { for(int i=0;i<5;i++) {
b1.setText(""+i);
Thread.sleep(5000);
runOnUiThread(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
pp();
}
}
});
}} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
th.start();
Here is the solution for this you need to add the following class in your code. And you can directly add a view to your XML file.
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
public class TimerTextView extends TextView {
private static final int DEFAULT_INTERVAL = 1000;
private Timer timer = new Timer();
private long endTime = 0;
private long interval = DEFAULT_INTERVAL;
private boolean isCanceled = false;
public TimerTextView(Context context) {
super(context);
}
public TimerTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TimerTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public TimerTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
stopTimer();
}
#Override protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (VISIBLE == visibility) {
startTimer();
} else {
stopTimer();
}
}
public void setInterval(long interval) {
if (interval >= 0) {
this.interval = interval;
stopTimer();
startTimer();
}
}
public void setEndTime(long endTime) {
if (endTime >= 0) {
this.endTime = endTime;
stopTimer();
startTimer();
}
}
private void startTimer() {
if (endTime == 0) {
return;
}
if (isCanceled) {
timer = new Timer();
isCanceled = false;
}
timer.scheduleAtFixedRate(new TimerTask() {
#Override public void run() {
if (null == getHandler()) {
return;
}
getHandler().post(new Runnable() {
#Override public void run() {
setText(getDurationBreakdown(endTime - System.currentTimeMillis()));
}
});
}
}, 0, interval);
}
private void stopTimer() {
timer.cancel();
isCanceled = true;
}
private String getDurationBreakdown(long diff) {
long millis = diff;
if (millis < 0) {
return "00:00:00";
}
long hours = TimeUnit.MILLISECONDS.toHours(millis);
millis -= TimeUnit.HOURS.toMillis(hours);
long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
millis -= TimeUnit.MINUTES.toMillis(minutes);
long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
return String.format(Locale.ENGLISH, "%02d:%02d:%02d", hours, minutes, seconds);
//return "${getWithLeadZero(hours)}:${getWithLeadZero(minutes)}:${getWithLeadZero(seconds)}"
}
}
You need to create a thread to handle the update loop and use it to update the textarea. The tricky part though is that only the main thread can actually modify the ui so the update loop thread needs to signal the main thread to do the update. This is done using a Handler.
Check out this link: http://developer.android.com/guide/topics/ui/dialogs.html#
Click on the section titled "Example ProgressDialog with a second thread". It's an example of exactly what you need to do, except with a progress dialog instead of a textfield.
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 ");
}
If anyone is interested, I started playing around with creating a standard object to run on an activities UI thread. Seems to work ok. Comments welcome. I'd love this to be available on the layout designer as a component to drag onto an Activity. Can't believe something like that doesn't already exist.
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;
}
}
In the activity, I have this onStart:
#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();
}
Here is a simple reliable way...
Put the following code in your Activity, and the tick() method will be called every second in the UI thread while your activity is in the "resumed" state. Of course, you can change the tick() method to do what you want, or to be called more or less frequently.
#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());
}
For those interested, the "_h0=_handler" code is necessary to avoid two timers running simultaneously if your activity is paused and resumed within the tick period.
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"/>
If you have delta time already.
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();
}
}
}
I Abstract Timer away and made it a separate class:
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);
}
}
And Extract main action from Timer class out as
IAction.java
public interface IAction {
void Task();
}
And I used it just like this:
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++;
}
});
}
...
}
I Hope This Helps 😊👌
I use this way:
String[] array={
"man","for","think"
}; int j;
then below the 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();
it's easy way to solve this problem.

Categories

Resources