Pausing with handler and postDelayed in android - android

I'm very new to android programming so please forgive my noobie-ness. I'm trying to create a very simple activity that will have one TextView in the middle of the Layout and just have it switch to a different text every couple of seconds. For example, the TextView will say "text1", pause for a couple of seconds, then say "text2, and pause again. Eventually, I want to add more texts and have them all cycle one after another. I know this seems like a super simple thing but I'm mainly trying to learn about threads and handlers at this moment. Anyways, I've read up on how we should keep lengthy things off the UI thread to prevent an error so I thought I'd use a handler to simply switch between 2 texts on screen. Unfortunately, I can't get this to work. Here's some code:
public class MainActivity extends Activity {
String[] myarray = {"text1" , "text2"};
int arraylength = myarray.length;
int count;
Handler handler = new Handler();
TextView mytexts;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mytexts = (TextView)findViewById(R.id.my_texts);
mytexts.setText(myarray[0]);
Thread t = new Thread( new Runnable(){
public void run() {
for (int count = 0; count < arraylength; count++){
handler.postDelayed(new Runnable(){
public void run() {
mytexts.setText(myarray[1]);
}
}, 7000);
}
}
});
t.start();
}
}
From what I can see in the logcat, the handler seems to run postDelayed one right after another (in my code's case, it does NOT wait 7 seconds with the postDelay to do another postDelayed). Also, I would like to make the 1 in "mytexts.setText(myarray[1]);" be the same as "count" in the for loop so it can be the same as one of the strings in the array but that gives me an error. I've been stuck on this for hours and other examples I've found online seem way too complicated for someone like me who mainly wants to get the basics down before I can tackle other things. Any help at all with any of this would be much appreciated. Thank you.

postDelayed is non blocking, meaning it would add it to a queue of I'll do this later. So what you are probably seeing is all text updates happening together at the 7th second. I say this because you are postDelaying from the onCreate method when in reality you probably want to do it from onResume or even onPostResume.
Also there is no reason to create a thread to add runnables to the post queue. Your code should look more like this:
(Note the time to delay multiplier)
#Override
protected void onResume() {
super.onResume();
for (int count = 0; count < arraylength; count++){
handler.postDelayed(new Runnable(){
#Override
public void run() {
mytexts.setText(myarray[count]);
}
}, 7000 * (count + 1));
}
}

This is because your loop is setting all your handlers to run after 7 seconds not 7 seconds after each other but but after 7 seconds from now. You can either add in the postDelayed method or use the postAtTime method in handler .
Also, you don't need to do this in a thread, you can get rid of that altogether.

Related

Using handler.postDelayed with "for"

Basically, I am trying to do something more complicated than that, but this is my problem:
When using handler.postDelayed inside a for loop, there's delay only on the first time, and I wait the delay to kick in every time the for loop repeats:
For example, in this case:
for(int z=0; z<4; z++) {
final int finalZ = z;
handler.postDelayed(new Runnable() {
#Override
public void run() {
Toast.makeText(play.this, "z:" + finalZ, Toast.LENGTH_SHORT).show();
}
}, 5000);
}
I will get:
Waiting 5 seconds.
z:0
z:1
z:2
z:3
What I want to get:
Waiting 5 seconds.
z:0
Waiting 5 seconds.
z:1
Waiting 5 seconds.
z:2
Waiting 5 seconds.
z:3
I was told not to use Thread.sleep() because it can cause various issues (I didn't quite understand them as I am new to android studio). I am using this in a certain activity (not my Main_Activity).
I am basically trying to change an image's color ever 0.5 seconds or so (more complications go into that, but that's the main idea). Will Thread.sleep() be better?
EDIT: Okay, so thanks to #tynn & #pskink I got this to work (see their answers). But now, another problem came up following this.
If, for example, I will run the exact same code after that, they will both run at the same time, and not one after another, how can i make the second "for" start only after the first "for" has ended?
Here another aspect
private int z=0;
Runnable r = new Runnable() {
#Override
public void run() {
Toast.makeText(play.this, "z:" + z, Toast.LENGTH_SHORT).show();
if(z<4){
z++;
handler.postDelayed(r, 5000);
}
}
}
handler.post(r);
The handler runs your code on another thread, independent of your for loop. The delay is relative to the point where you posted the runnable. Not relative to the previous post. Also it doesn't block the for loop at all. That's the purpose of handlers.
You can assume that any post in this scenario happens at the same time, so you could just do handler.postDelayed(runnable, (z + 1) * 5000). Or maybe define the execution time as absolute with handler.postAtTime(runnable, firstRun + z * 5000)
But since you're trying to do something more complicated than that, you should better consider using a Timer or similar. Maybe RxJava.
Your current code works like this:
hey handler, do it after 5s,
oh and do it after 5s too,
and do it after 5s too,
and this plz do after 5s.
Then we wait 5s and handler is doing those actions in one moment.
What you can do is change it to:
hey handler, do it after 5s,
oh and do it after 10s,
and this after 15s
...
Or you can do it like this:
hey handler do it after 5s, where 'it' action is 'hey handler do it after 5s'.
Then handler will wait 5s and call action 'hey handler do it after 5s'. So handler will have to wait again 5s and do some action after that time.
Here is code for my aproach:
final int finalZ = z;
delayedAction(handler, 0, z);
. . .
void delayedAction(final Handler handler, final int i, final int max) {
if(i<max) {
Toast.makeText(play.this, "z:" + finalZ, Toast.LENGTH_SHORT).show();
handler.postDelayed(new Runnable() {
#Override
public void run() {
delayedAction(handler, i+1, max);
}
});
}
}

How to use android handler in a loop

I am building my first android application and I am trying to make a memory game. Anyhow, I need to make an array of buttons change color for 1 second and then return to its original color in order, for example: button1 changes to yellow, stays like that for 1 second then returns to gray, then button2 changes to yellow for 1 second then returns, and so on. I tried using the handler but it always works only after the last iteration, this is my code:
for (i = 0; i < 9; i++) {
buttonList.get(i).setBackgroundColor(Color.YELLOW);
runnable =new Runnable(){
#Override
public void run() {
buttonList.get(i).setBackgroundColor(Color.GRAY);
}
};
handler.postDelayed(runnable,1000);}
what am I doing wrong?
EDIT
Found How to do it. First I need to make a runnable class that takes paramaters ex MyRunnable implements Runnable (using Runnable interface), then writing a method that uses this paramater, I can't do it with the regular one because it depends on i and i changes with the iteration.
You need to create a new Runnable inside each loop because all 9 delayed posts are running the same runnable that you create on the 9th and final loop since the loop no doubt takes less than a second to complete. So try something like this:
for (i = 0; i < 9; i++) {
buttonList.get(i).setBackgroundColor(Color.YELLOW);
Runnable runnable = new Runnable(){
#Override
public void run() {
buttonList.get(i).setBackgroundColor(Color.GRAY);
}};
handler.postDelayed(runnable,1000);
}
You're synchronously (at the same time) setting all buttons' colors to yellow, and also creating 9 asynchronous tasks (one for each button) to change color to gray after one second. It means all buttons will change colors back to gray after around 1 second, (more or less) at the same time.
Think of the handler as a queue that you add tasks to. The call postDelayed() is scheduling your tasks to be executed in the future, but all of them are scheduled at the same time, so all of them will be executed at the same time in the future.
I haven't run it, but I think this approach is more of what you are looking for:
// Those are fields
private int buttonIndex = 0;
private boolean yellow = false;
private final Handler handler = new Handler(new Handler.Callback() {
#Override
public void handleMessage(Message msg) {
if (!yellow) {
buttonList.get(buttonIndex).setBackgroundColor(Color.YELLOW);
handler.sendEmptyMessageDelayed(0, 1000);
} else {
buttonList.get(buttonIndex).setBackgroundColor(Color.GRAY);
if (++buttonIndex < 9) handler.sendEmptyMessage(0);
}
yellow = !yellow;
}});
// Call this to start the sequence.
handler.sendEmptyMessage(0);
Note that I'm using sendEmptyMessage*() instead of post*(), but either approach could be used. Additionally, handler's messages (tasks) can have input parameters, so it'd be nice to use them.

Android postDelayed does not delay

I have the Problem that my Android app does not delay a second (or 10 seconds), if I use the postDelayed method..
Basically I would like my program to wait one second after I clicked the button, then update the text on my textview ("READY"), wait another 2 seconds, then update the textview again ("SET") and then it should start another activity (not yet implemented :-) ).
With my code, the programm starts and after I click the button the textview shows the last text ("SET") immediately.. It just does not wait.
What am i doing wrong?
Here is my code:
public class MyCounterActivity extends Activity {
private long mInternval = 100000;
private Handler mHandler;
private Runnable mStatusChecker = new Runnable() {
#Override
public void run() {
//updateInterval(); //change interval
startRepeatingTask();
}
};
void startRepeatingTask(){
mHandler.postDelayed(mStatusChecker, mInternval);
//mStatusChecker.run();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gym_counter);
final TextView tv1 = (TextView) findViewById(R.id.fullscreen_content);
final Button startButton = (Button) findViewById(R.id.startbutton);
startButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final long up;
EditText textUp = (EditText) findViewById(R.id.editTextUp);
up = Integer.parseInt(textUp.getText().toString());
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//
}
},1000);
Log.d("after 1 runnable", "whaaat");
tv1.setText("Ready");
handler.postDelayed(new Runnable() {
#Override
public void run() {
//
}
}, 2000);
Log.d("after 2nd runnable", "whaaat 2");
//startRepeatingTask();
tv1.setText("SET");
}
});
}
I also tried to run it with the runOnUiThread() (within the onClick(View v) but with with the same result). I expected it to wait 1 second (startRepeatingTask()) and then runs the loop and waits several seconds...
runOnUiThread(new Runnable() {
#Override
public void run() {
startRepeatingTask();
for (int u = 0; u < up; u++){
startRepeatingTask();
}
}
}
});
Hope my description makes sense :-).
Thank you for your help!
EDIT:
I was now able to find a solution for my first problem. The answer from #mad in this post helpded me: How to start a different activity with some delay after pressing a button in android?
(Thats probably the same thing that #laalto tried to tell me. Thanks for the hint!)
In the onClick()
tv1.setText("READY");
mHandler.postDelayed(mDelay1, 2000);
And then the Runnable
private Runnable mDelay1 = new Runnable() {
#Override
public void run() {
if (tv1.getText()=="READY")
tv1.setText("SET");
}
};
BUT:
If i want to refresh the text on my Textview after every second, how do i do that? I cant just call mHandler.postDelayed() several times.. Any help is appreciated.
When you call postDelayed(), it just places the Runnable in a queue and returns immediately. It does not wait for the runnable to be executed.
If you need something to happen after a delay, put the code in the run() method of the runnable.
Whenever you call something like Thread.start(), handler.postDelayed, view.postDelayed, AsynchTask, TimerTask .. you enter the world of threading or you might call it parallel computing.
So there can be multiple threads ("codes") running at the same time.
When you are inside your Activity it is running in a Thread that is calld UI-thread or main thread. All graphics is handled in that thread and that thread alone.
Do NEVER wait in the UI-thread!
Example: you have a button that switches color from say gray to yellow on pressing it. Now you enter a Thread.sleep(10000); - waiting 10 seconds at the start of your onClick.
You will then see that the button stays yellow (=pressed) for 10 seconds even if you only pressed very shortly. Also: if you overdo it android os will become angry and post the user if he wants to force-close your app.
So what happens on handler.postDelayed?
Android will very quickly open a thread that runs in the background parallel to your UI thread. So in some nanoseconds it has done that and will execute the next command in UI thread (in the example above it is Log.d). In the background it will wait and count the millis until time is up. Then any code that is inside the runnable.run method will again be executed in the ui-thread after the wait.
Note also: postDelayed will not be super precise with the wait time as usually the ui-thread is quite buisy and when the wait time is up it may have something else to do. Your runnable code will be added to a queue and executed when ui-thread is ready again. All this happens without you having anything to do about it.
Also:
Remember to work with try/catch inside the runnable.run as many things can happen while waiting - for example user could press Home button closing your app - so the ui-element you wanted to change after the wait could already been destroyed.

Implementing a while loop in android

I can't understand the implementation of a while loop in android.
Whenever I implement a while loop inside the onCreate() bundle, (code shown below)
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
TextView=(TextView)findViewById(R.id.TextView);
while (testByte == 0)
updateAuto();
}
nothing boots up, and the program enters a "hanging" state after a while and I can't understand why. Testbyte is as follows:
byte testByte == 0;
and updateAuto() is supposed to update the code per 1 second and display inside the textView portion. I've been using setText inside updateAuto() as shown below and everything works fine, but once i implement the while loop all i see is a black screen and then an option to force close after a few seconds due to it "not responding".
TextView.setText(updateWords);
I've changed it to a button format (meaning i have to click on the button to update itself for now), but i want it to update itself instead of manually clicking it.
Am i implementing the while loop in a wrong way?
I've also tried calling the while loop in a seperate function but it still gives me the black screen of nothingness.
I've been reading something about a Handler service... what does it do? Can the Handler service update my TextView in a safer or memory efficient way?
Many thanks if anyone would give some pointers on what i should do on this.
Brace yourself. And try to follow closely, this will be invaluable as a dev.
While loops really should only be implemented in a separate Thread. A separate thread is like a second process running in your app. The reason why it force closed is because you ran the loop in the UI thread, making the UI unable to do anything except for going through that loop. You have to place that loop into the second Thread so the UI Thread can be free to run. When threading, you can't update the GUI unless you are in the UI Thread. Here is how it would be done in this case.
First, you create a Runnable, which will contain the code that loops in it's run method. In that Runnable, you will have to make a second Runnable that posts to the UI thread. For example:
TextView myTextView = (TextView) findViewById(R.id.myTextView); //grab your tv
Runnable myRunnable = new Runnable() {
#Override
public void run() {
while (testByte == 0) {
Thread.sleep(1000); // Waits for 1 second (1000 milliseconds)
String updateWords = updateAuto(); // make updateAuto() return a string
myTextView.post(new Runnable() {
#Override
public void run() {
myTextView.setText(updateWords);
});
}
}
};
Next just create your thread using the Runnable and start it.
Thread myThread = new Thread(myRunnable);
myThread.start();
You should now see your app looping with no force closes.
You can create a new Thread for a while loop.
This code will create a new thread to wait for a boolean value to change its state.
private volatile boolean isClickable = false;
new Thread() {
#Override
public void run() {
super.run();
while (!isClickable) {
// boolean is still false, thread is still running
}
// do your stuff here after the loop is finished
}
}.start();

How to set an image with a delay

I have an "Activity" with three images. When one image is clicked, all the images are to switch to another picture. Is there a way to make the switches such that there is a 2 second delay before the images actually change (i.e. a 2 second delay in every 'for loop' below)? I am trying to do this with a timer but it does not actually to the delay when I run my program:
protected void onCreate(Bundle savedInstanceState) {
image1.setOnClickListener(this);
#Override
public void onClick(View arg0)
{
do_switches();
}
private void do_switches()
{
//loop through all images and change them
for(int j=1 ;j<=3; j++)
{
final int curr2=current;
final Handler handler = new Handler();
Timer t = new Timer();
t.schedule(new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
switch(curr2){
case 1:
image1.setImageResource(ImageArray[1]);
break;
case 2:
image2.setImageResource(ImageArray[2]);
break;
case 3:
image3.setImageResource(ImageArray[3]);
break;
}
}
});
}
}, 2000);
}
}
I have also tried using just SystemClock.sleep(2000) instead of the timer but I that didnt work either.I also tried setting up a Thread with a try/catch with no luck or maybe I didn't implement it properly. Is there a way to put this delay on every iteration of my for loop?
Thanks
Not one of best option, but still you can try CountDownTimer.
http://developer.android.com/reference/android/os/CountDownTimer.html
You can use handler.postDelayed(Runnable r, long timeInMillis). Make your runnable that changes the pictures and then call postDelayed() and pass in the runnable and 2000 for the time delay.
Edit: Ahh I see what you are trying to do. As far as I know you aren't going to be able to make a for loop pause for 2 seconds each time through. You can get the same effect though if you chain the postDelayed() calls. Just set up the next runnable and call postDelayed() on it inside the first one, and same for the third one from inside the second one. You will end up with the same functionality as a for loop that pauses for 2 seconds each iteration.

Categories

Resources