I'm trying to update the background color of a few TextView
s in my Android application. I want to set each color with a short pause in between, ie:
<set TextView one's background to gold>
<pause 500ms>
<set TextView two's background to gold>
<pause 500ms>
<set TextView three's background to gold>
<pause 500ms>
The goal is to make some sort of progressive highlighting pattern across the boxes.
The issue that I'm having is all the boxes are updating at once, after the pause. I've read that if I want to force the view to draw itself I need to call invalidate()
and I've tried that, but it didn't seem to do anything. I'm not sure if either the method I'm using to sleep is causing the issues, or if I'm not forcing the draw update with the correct method. Hopefully someone can point me in the right direction:
Resources res = getResources();
for(int i=0; i<3; i++){
int id = res.getIdentifier("txt"+Integer.toString(box[i]), "id",
getApplicationContext().getPackageName());
TextView temp = (TextView)findViewById(id);
// Set gold with 50% opacity
temp.setBackgroundColor(Color.parseColor("#ffd700"));
temp.getBackground().setAlpha(127);
// Force redraw
temp.invalidate();
// Sleep for half a second
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Note: I want the main thread blocked until this sequence of background changes is updated, nothing should happen until these three TextView
s have been updated, that's why I'm calling sleep()
from the main UI thread.
EDIT
I attempted to use a runnable while "blocking" my main thread to do the updates in the background. If this is the way it should be handled maybe someone can point out to me where I'm going wrong:
boolean moveon;
//...
onCreate() {
moveon = false;
//...
Handler myh = new Handler();
Runnable myr = new Runnable() {
public void run() {
Resources res = getResources();
for(int i=0; i<3; i++){
id = res.getIdentifier("txt"+Integer.toString(winners[i]), "id",
getApplicationContext().getPackageName());
TextView temp = (TextView)findViewById(id);
temp.setBackgroundColor(Color.parseColor("#ffd700"));
temp.getBackground().setAlpha(127);
temp.invalidate();
}
moveon = true;
}
};
myh.post(myr);
while(moveon == false){} //blocks forever here, perhaps the update to from the
// runable doesn't propagate?
Going to take the comments I made and post them here as well:
"I want the main thread blocked" -- No, you want the UI disabled during the period, not blocked, which is why they're all occurring at once. A better option would be a global boolean, let's call it "enabled," and set that to false during the operation, then to true when the updates have completed, while calling postInvalidate() from the secondary thread. Then in your UI thread you should check to see if enabled is equal to true before allowing any additional operations to take place. This will create the illusion of being blocked without it actually being blocked
Now, taking your code:
boolean moveon;
//...
onCreate() {
moveon = false;
//...
Handler myh = new Handler();
Runnable myr = new Runnable() {
public void run() {
Resources res = getResources();
for(int i=0; i<3; i++){
id = res.getIdentifier("txt"+Integer.toString(winners[i]), "id",
getApplicationContext().getPackageName());
TextView temp = (TextView)findViewById(id);
temp.setBackgroundColor(Color.parseColor("#ffd700"));
temp.getBackground().setAlpha(127);
temp.invalidate();
}
moveon = true;
}
};
myh.post(myr);
while(moveon == false){}
You're close:
boolean moveon;
//...
onCreate() {
moveon = false;
//...
// Still in UI thread here
Handler myh = new Handler();
final Resources res = getResources(); // final so we can access it inside second thread
new Thread(new Runnable() {
public void run() {
// In second thread
for(int i=0; i<3; i++){
// Now we use the Handler to post back to the UI thread from the second thread
myh.post(new Runnable() {
public void run() {
// In UI thread, update here and then invalidate
id = res.getIdentifier("txt"+Integer.toString(winners[i]), "id",
getApplicationContext().getPackageName());
TextView temp = (TextView)findViewById(id);
temp.setBackgroundColor(Color.parseColor("#ffd700"));
temp.getBackground().setAlpha(127);
temp.postInvalidate();
}
});
Thread.sleep(delayMs); // Sleep second thread
}
myh.post(new Runnable() {
public void run() {
// In UI thread, reset the moveon to true on correct thread
moveon = true;
}
});
}
}).start();
Then don't use your while-loop, as that will still just block the UI and give you the same problem. What you want to do instead is check if moveon == true before allowing the user to do anything else; no loop necessary.