Thread issues with handler in android - java

One part of my activity needs two timers running at once, one of them using Handler and the other using CountDownTimer. The handler portion updates the display every second, while the CountDownTimer counts down to when this part of the code ends. For some reason, I cannot run these both at the same time, and even when I commented out the CountDownTimer portion, the handler portion only ran once, instead of repeating every second. I am at a loss for what to do here. Any ideas? The relevant part of the code is below. For some clarification, the first handler seen here is supposed to run on its own, until a condition is met, at which point it reruns the function and goes to the second if statement. Seen within the second if statement are the details I mentioned at the beginning.
private void statusCheck() {
if (possible = true) {
final Random random = new Random();
final Handler handler1 = new Handler();
final int delay1 = 1000; //milliseconds
handler1.postDelayed(new Runnable() {
public void run() {
runChance = random.nextInt(1000);
if (runChance < 100) {
possible = false;
statusCheck();
}
}
}, delay1);
}
if (possible = false) {
final Handler Handler = new Handler();
final int Delay = 1000; //milliseconds
Handler.postDelayed(new Runnable() {
public void run() {
// code to update every second
}
}, Delay);
new CountDownTimer(ghostDuration, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//code to run when finished
}
}.start();
}
}

First of all it's not a good idea to to run timer and tasks under Android that way.
Android will block these timer and tasks because they work against the framework.
If you want to implement it correctly with a WorkManager watch out this video from Google which gives you some fundamentals: Android Jetpack WorkManager

Related

handler.postDelayed is not working(android eclipse)

I am trying to make a delay after playing the set of sounds in mediaplayer so that it won't overlap. i have tried thread.sleep and it worked but the problem is I have a button for sound to stop but because of the thread.sleep, it is not working so i searched and tried for an alternative way in which i can make a delay without locking the UI and i came up with handler.postDelayed but it is not working. is there anyone who can help me solve this problem? thanks in advance.
here is my code:
protected void managerOfSound() {
int size = tempq.size();
for (int i = 0; i < tempq.size(); i++) {
String u =tempq.get(i);
//WHOLE
if (u.equals("a4")){
mp = MediaPlayer.create(this, R.raw.a4);
mp.start();
final Runnable r = new Runnable() {
public void run() {
handler.postDelayed(this, 2000);
}
};
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
// stuff you wanna delay
}
}, 2000);
The postDelayed(Runnable r, long delayMillis ) causes the Runnable to be added to the message queue, to be run after the specified amount of time elapses. The runnable will be run on the thread to which this handler is attached ( int htis case the UI thread) . The time-base is uptimeMillis(). Time spent in deep sleep will add an additional delay to execution.
Reference : Android API documentation

Java Timer equivalent in Android

I recently began working with Java and am exploring Android development. I was trying to port over one of the Java programs I made, but I am having some difficulty with getting the java Timer to function the same way in Android. I read through a number of posts and they, for the most part, indicated that it would be better to use the Handler class in android as opposed to Timer.
This was my timer in Java:
playTimer = new Timer(1000/model.getFPS(), new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// do something
...
if( finished everything ) playTimer.stop();
}
});
And once a certain button was clicked, I would simply run "playTimer.start()" to start it.
As you can see, I had it set up so that the user could set the FPS they wanted (by simply setting the first parameter of the Timer class to 1000/model.getFPS()).
Now I've tried to do something similar in Android using handlers, but I am having some difficulty. It appears that the Handler ticks are not firing at the proper intervals. It seems that they are quite slow compared to what I need it to be. This is what I did in android so far:
public void startTimer() {
playHandler = new Handler();
startTime = System.currentTimeMillis();
playHandler.removeCallbacks(updateTimeTask);
playHandler.postDelayed(updateTimeTask, 0);
}
private Runnable updateTimeTask = new Runnable() {
public void run() {
// do something
...
if( finished everything ) playHander.cancel();
else {
playHandler.postDelayed(updateTimeTask, 1000/model.getFPS());
}
}
};
Excuse the semi-pseudocode. Can anyone shed any light? Thanks guys.
You can use a timer as below. The timer runs every second incrementing the counter. Displs the counter value in textview.
Timer runs on a different thread. SO you should set the text on the UI Thread.
The counter runs from 0 to 99. After 99 the timer is cancelled. Also cancel the timer when not required like in onPause().
public class MainActivity extends Activity {
TextView _tv,tv2;
Timer _t;
int _count=0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
_tv = (TextView) findViewById( R.id.textView1 );
_t = new Timer();
_tv.setText(R.string.app_name);
_t.scheduleAtFixedRate( new TimerTask() {
#Override
public void run() {
_count++;
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
_tv.setText(""+_count);
if(_count==99)
{
_t.cancel();
}
}
});
}
}, 1000, 1000 ); //change this value of 1000 to whatever you need.
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
_t.cancel();
}
}
If you decide not to use Timer (for whatever reason) you can just write a separate Thread that sleeps for x milliseconds and then wakes up and calls whatever Runnable you want it to call. That's going to be pretty precise. I have it working at the 10 millisecond level and it works quite nicely.
Just remember that it HAS to call a Runnable because a separate Thread can't have direct effect on anything on the main display thread.
public boolean keepPlayingAnimation = true
Handler h = new Handler()
Runnable updateDisplay = new Runnable(){
public void run(){
//do something in my display;
}
}
new Thread(){
public void run(){
while(keepPlayingAnimation){
try{
sleep(10);
}catch(Exception e){
}
h.post(updateDisplay);
}
}
}.start();
Just don't forget to set keepPlayingAnimation to false when you're done with this cause otherwise it will sit there running in the background for ever (or just about).
Take a look at Android Timer
It already has everything you need i guess. From ticking every 1 second to finish handly and so on.
Here is an example how to setup an TimerTask: setup
Not sure if you need such but i just remembered that i made this.

If function appending loading message more than once

I have a loading screen, I want to display the loadingMessage1 for 3 secs than shows loading message 2. I only want loading message 2 to appear once, but when I tried to do it, loading message 2 kept getting appended in an endless loop.
So i tried put a count variable to increases after every loading message 2 append, but it doesnt work. where am i going wrong, is there another solution to this?
final TextView loadingMessage1 = (TextView)this.findViewById(R.id.loadingMessage1);
int count = 0;
final Handler handler = new Handler();
if (count == 0){
handler.post(new Runnable(){
#Override
public void run(){
loadingMessage1.append("Loading Message 2");
handler.postDelayed(this, 3*1000L);
}
});
count++;
}
You are making a mistake on the following line:
handler.postDelayed(this, 3*1000L);
Here you send to this Runnable object to the handler while handling this. That means when you fist execute the Runnable, on the end you add it again to the handler's message loop. Thus you obtained an infinite loop. Something of the like will solve your problem:
final TextView loadingMessage1 = (TextView)this.findViewById(R.id.loadingMessage1);
int count = 0;
final Handler handler = new Handler();
handler.postDelayed(new Runnable(){
#Override
public void run(){
loadingMessage1.append("Loading Message 2");
}
}, 3*1000L);
EDIT:
To make all this stuff flexible, do the following:
// inner class
class TextChanger implements Runnable {
private final String message;
public TextChanger(String message) {
this.message = message;
}
#Override
public void run() {
loadingMessage1.append(message);
}
}
and then somewhere in your code:
public static final long TIME_CONSTANT = 3*1000L;
final TextView loadingMessage1 = (TextView)this.findViewById(R.id.loadingMessage1);
int count = 0;
final Handler handler = new Handler();
handler.postDelayed(new TextChanger("Whatever 1"), TIME_CONSTANT);
handler.postDelayed(new TextChanger("Whatever 2"), 2 * TIME_CONSTANT);
and so on. The trick is not to reference this as you did before, because it creates an infinite loop.
You need to avoid posting another event after each execution. Perhaps something more like this:
void showMessage1() {
// ... code to show message 1 ...
handler.postDelayed(new Runnable(){
#Override
public void run(){
showMessage2();
}
}, 3*1000L);
}
void showMessage2() {
// ... code to show message 2 ...
}
Note that message-showing code only executes once per message.

Why is my countdown timer in Android so slow?

I'm trying to make a countdown timer in android for use in a small android app. The app will countdown from some number of seconds to 0, upon which it will do some action. I'm using the coundowntimer supplied by android.os.countdowntimer. Here is my code:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.quizlayout);
new CountDownTimer(30000, 1000) {
TextView tx = (TextView) findViewById(R.id.textView2);
public void onTick(long millisUntilFinished) {
tx.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
tx.setText("done!");
}
}.start();
}
However, this countdown timer is really slow. It takes like 3 real-time seconds for the timer to countdown by one second. I wonder what's going on? The code I have above is more or less copied straight from google (CountDownTimer)
Can anyone help me as per why my timer is so slow, and offer a way to speed it up a bit?
(EDIT): I am running this on an emulator, the intel atom x86. I am emulating an android 2.3.3 environment.
According to Android documentation for countdown timer
The calls to onTick(long) are synchronized to this object so that one call to onTick(long) won't ever occur before the previous callback is complete. This is only relevant when the implementation of onTick(long) takes an amount of time to execute that is significant compared to the countdown interval.
Take a look at this example for countdown timer
Countdown timer example
Alternately you can spawn a new thread and just get that thread to sleep for the interval you want and take actions when it wakes or vice versa.
You can also timertask
use a handler that will post the same runnable . this will remove the need for extra threads :
Handler handler=new Handler();
handler.postRunnable(... , 1000) ;
in the runnable , call the postRunnable again for the same handler (and add a condition for when to stop) .
CountDownTimer is not efficient regardless to ui updating performances. For a flawless ui update, it is better to create a custom countdown. I did my own so here it is. It is flawless on my app.
public abstract class CountDown {
int totalTime = 0;
int tickTime = 0;
Thread thread;
boolean canceled = false;
public CountDown(int totalTime,int tickTime){
this.totalTime = totalTime;
this.tickTime = tickTime;
}
public abstract void onTick();
public abstract void onFinish();
public void start(){
thread = new Thread(new Runnable() {
#Override
public void run() {
// Do in thread
canceled = false;
for (int elapsedTime = 0; elapsedTime < totalTime; elapsedTime += tickTime) {
if(!canceled){
onTick();
try {
thread.sleep(tickTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
break;
}
}
if(!canceled){
onFinish();
}
}
});
thread.start();
}
public void cancel(){
canceled = true;
}
}
Remember that every time you have to update your ui, call a runOnUiThread, or else you will have an exception, you are not in a handler and not on ui thread.
Here is how to use it in your code, it is identical to CountDownTimer, so you could just rename lines in your code :
CountDown cDown = new CountDown(10000, 20) {
public void onTick() {
// Do something
}
public void onFinish() {
runOnUiThread(new Runnable() {
#Override
public void run() {
myButton.setImageDrawable(drawable);
}
});
}
};

Android timer/timertask causing my app to crash?

Just testing out a simple block of code in my mainActivity's onCreate:
Timer timer2 = new Timer();
TimerTask testing = new TimerTask() {
public void run() {
Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();
}
};
timer2.schedule(testing, 1000);
I get the "force close" error though.
What gives?
Alright for anyone else who runs into this, I fixed the problem by using a Handler and Runnable to do the Toast, which seems to be needed for UI interaction:
final Handler handler = new Handler();
Timer timer2 = new Timer();
TimerTask testing = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();
}
});
}
};
timer2.schedule(testing, 1000);
I still don't understand why this is necessary though, perhaps someone could explain? But hey at least this code works lol.
Timer(Tasks) are bad! Do it the Android way: Use a Handler.
As you can see in the code snippet, it’s pretty easy to go that way too:
First we need a Handler that starts the Runnable after 100ms
private Handler handler = new Handler();
handler.postDelayed(runnable, 100);
And we also need the Runnable for the Handler
private Runnable runnable = new Runnable() {
#Override
public void run() {
/* do what you need to do */
foobar();
/* and here comes the "trick" */
handler.postDelayed(this, 100);
}
};
So the “trick” is to tell the handler at the end to start the Runnable again. This way the runnable is started every 100ms, like a scheduleAtFixedRate() TimerTask! If you want it to stop, you can just call handler.removeCallback(runnable) and it won’t start again, until you tell it to
This exact issue is discussed in this article:
http://developer.android.com/resources/articles/timed-ui-updates.html
The app crashes because you are attempting to access elements of the UI thread (a toast) from a different thread (the timer thread). You cannot do this!
You can get round it by either:
Sending a handler message from the timer thread to the UI thread, and then showing the toast in the UI handler function.
OR
In the timer code run use 'runOnUiThread':
#Override
public void run()
{
mainActivity.runOnUiThread(new Runnable() {
public void run() {
// Access/update UI here
Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();
}
});
}
#YoungMoney
It works but only the first time... Did you make it display the Toast message every second??
Mine only worked once...
===
Edit:
Just realised your last line of code is missing the last value which is how often to repeat.
For anyone else concerned, change this:
timer2.schedule(testing, 1000);
to this:
timer2.schedule(testing, 1000, 2000);
If you want to start the timer in 1 second, and update every 2 seconds.
TimerTask task = new TimerTask() {
#Override
public void run() {
//do something
}
};
Timer t = new Timer();
t.schedule(task, 2000);

Categories

Resources