Change a View from inside a Timer Function - java

I need to have my TextView be blue for half a second, and then turn white again (user clicks, it blinks blue).
To do this, I tried setting the colour to blue, setting a 500ms timer, and then changing it back to white. Like this:
// defining the TextView
final TextView showDatabase = new TextView(this);
showDatabase.setText("Show Database");
showDatabase.setTextColor(Color.WHITE);
// click listener
showDatabase.setOnClickListener (new View.OnClickListener() {
public void onClick(View v) {
showDatabase.setTextColor(Color.BLUE); // make it blue
// wait 500ms, then make it white again
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
showDatabase.setTextColor(Color.WHITE);
}
}, 500);
}
});
Logcat:
Only the original thread that created a view hierarchy can touch its views.
I can't simply create an instance of the TextView inside the timer function (I think) because it's not an element on a layout.
How can I let myself manipulate the TextView from inside the timer function?

Timer runs on a different thread. You cannot update ui from there. Use a Handler or runOnUiThread.
runOnUiThread(new Runnable() {
#Override
public void run() {
showDatabase.setTextColor(Color.WHITE);
}
});
Using Handler
Handler m_handler;
Runnable m_handlerTask ;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
showDatabase.setTextColor(Color.WHITE);
m_handler.postDelayed(m_handlerTask, 500);
}
};
m_handlerTask.run();
To cancel
m_handler.removeCallbacks(m_handlerTask);

Add a runOnUiThread in your timer:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// do UI updates here
}
});
}
}, 500);

Related

How to create new instance of TimerTask for Resume Button? (ERROR: TimerTask is scheduled already)

Good morning! I'm trying to do a pause button for my game, but having problems with initializing the timer task again when I want to resume the game.
I get the error "java.lang.IllegalStateException: TimerTask is scheduled already", which according to my research is because the TimerTask cannot be reused so a new instance must be created of it. I tried making a method in my MainActivity that would be used for this purpose, however, that did not work. This is what I'm working with:
public class MainActivity extends AppCompatActivity{
public FishView gameView;
//pause variables
Button pauseButton;
private boolean pauseFlag = false;
private final long animationPeriod = 600;
Timer movementTimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
screen = findViewById(R.id.gameScreen);
gameView = new FishView(this);
screen.addView(gameView);
pauseButton = findViewById(R.id.pauseButton);
movementTimer = new Timer();
movementTimer.scheduleAtFixedRate(animationTask, 0, animationPeriod);
}
//this is the timer I want to reuse
private TimerTask animationTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
//set animation
int selectedFish = gameView.getSelectedFish();
if (selectedFish==1){
gameView.setSelectedFish(0);}
if (selectedFish==0){
gameView.setSelectedFish(1); }
//update screen
gameView.invalidate();
}
});
}
};
public void pauseGame(View v){
String resume = "Resume";
String pause = "Pause";
if (!pauseFlag){
System.out.println("Turning timer of");
pauseFlag = true;
pauseButton.setText(resume);
movementTimer.cancel();
movementTimer=null;
}
else{
System.out.println("Starting timer again");
pauseFlag=false;
pauseButton.setText(pause);
try{
movementTimer = new Timer();
TimerTask newAnimationTask; //this did not work
createNewAnimationTask(newAnimationTask); //this did not work
movementTimer.scheduleAtFixedRate(animationTask, 0, animationPeriod); //here is where the error occurs
}
catch (Exception e){
System.out.println("ERROR: " + e);}
}
}
//attempted to make method that would generate new TimerTasks
public void createNewAnimationTask(TimerTask newAnimationTask){
newAnimationTask = new TimerTask() {
#Override
public void run(){
handler.post(new Runnable() {
#Override
public void run() {
System.out.println("Animation at work");
//here we set the animation
int selectedFish = gameView.getSelectedFish();
if (selectedFish==1){
gameView.setSelectedFish(0);}
if (selectedFish==0){
gameView.setSelectedFish(1); }
//update screen
gameView.invalidate();
}
});
}
};
}
}
What I'm wondering is how do I create a new TimerTask (like the "animationTask"), whenever I press the resume button?
I solved it. I removed all the TimerTask and just created everything in a function, like so:
public void createNewAnimationTask(){
movementTimer = new Timer();
TimerTask newAnimationTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
System.out.println("Animation at work");
//here we set the animation
int selectedFish = gameView.getSelectedFish();
if (selectedFish==1){
gameView.setSelectedFish(0);}
if (selectedFish==0){
gameView.setSelectedFish(1); }
//update screen
gameView.invalidate();
}
});
}
};
movementTimer.scheduleAtFixedRate(newAnimationTask, 0, animationPeriod);
}
Try adding the purge command also like;
movementTimer.cancel();
movementTimer.purge();

Automatically reset timer when the current item of view pager is last page

I want to implement an image slider with viewpager. The slider should automatically scroll horizontally. So I use a timer as below:
final Handler handler = new Handler();
final Runnable Update = new Runnable() {
public void run() {
if (currentPage == NUM_PAGES-1) {
currentPage = 0;
timer.cancel();
timer = new Timer();
}
mPager.setCurrentItem(currentPage++, true);
}
};
timer = new Timer(); // This will create a new Thread
timer .schedule(new TimerTask() { // task to be scheduled
#Override
public void run() {
handler.post(Update);
}
}, 500, 3000);
mPager is the viewpager which already has been set.
The problem is that when it reaches the last item (image), it stops there and doesn't scroll anymore. Another thing, when I scroll it manually to the first page, it suddenly scrolls to the last page ignorant of timer.
Any help would be appreciated.
You can try this,
final Handler handler = new Handler();
final Runnable Update = new Runnable() {
public void run() {
int currentPage = mPager.getCurrentItem();
if (currentPage == NUM_PAGES-1) {
currentPage = 0;
} else {
currentPage++;
}
mPager.setCurrentItem(currentPage, true);
handler.postDelayed(this, 5000);
}
};
handler.postDelayed(Update, 500);

How to change android timer period?

I am writing simple game, where some action must accelerating during the process. The question is how to change timer's period?
timer = new Timer();
timerTask = new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
//
// I need to change timer's period here
//
}
});
}
};
timer.schedule(timerTask, 0, period);
Will be glad to hear any advices.
I assume that you are performing some logic within the run() method of the TimerTask.
I think a simpler way to go about this would be to use a Handler. This is possibly more idiomatic for Android:
private final Handler mHandler = new Handler();
private final Runnable mTask = new Runnable() {
#Override
public void run() {
// Do your logic.
// Now post again.
mHandler.postDelayed(mTask, /* choose a new delay period */);
}
};
public void init() {
delay = 1000L; // 1 second.
mHandler.postDelayed(mTask, delay);
}

How to delay a loop in android without using thread.sleep?

I wanted to delay a for loop without using Thread.sleep because that method make my whole application hang. I tried to use handler but it doesn't seems to work inside a loop. Can someone please point out the mistake in my code.
public void onClick(View v) {
if (v == start)
{
for (int a = 0; a<4 ;a++) {
Handler handler1 = new Handler();
handler1.postDelayed(new Runnable() {
ImageButton[] all= {btn1, btn2, btn3, btn4};
btn5 = all[random.nextInt(all.length)];
btn5.setBackgroundColor(Color.RED);
#Override
public void run() {
}
}, 1000);
}
}
}
Basically what I wanted to do is that I got 4 ImageButton and I change each of their background to red by using a loop in order. Thats why I need a delay inside my loop, if not all the ImageButton will just directly turn red without showing which ImageButton turn first.
Your for loop should be:
final ImageButton[] all= {btn1, btn2, btn3, btn4};
Handler handler1 = new Handler();
for (int a = 1; a<=all.length ;a++) {
handler1.postDelayed(new Runnable() {
#Override
public void run() {
ImageButton btn5 = all[random.nextInt(all.length)];
btn5.setBackgroundColor(Color.RED);
}
}, 1000 * a);
}
}
This way it achieves your desired behavior of staggering the color change.
Edited for syntax
You can use a Handler instead of for loop. You should not call Thread.sleep() on the UI thread.
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
// do something
handler.postDelayed(this, 1000L); // 1 second delay
}
};
handler.post(runnable);
The following code doing the task in every second:
final Handler handler = new Handler();
Runnable task = new Runnable() {
#Override
public void run() {
Log.d(TAG, "Doing task");
handler.postDelayed(this, 1000);
}
};
handler.post(task);
Try this :
public void onClick(View v) {
if (v == start) {
for (int a = 0; a<4 ;a++) {
Handler handler1 = new Handler();
handler1.postDelayed(new Runnable() {
ImageButton[] all= {btn1, btn2, btn3, btn4};
#Override
public void run() {
btn5 = all[random.nextInt(all.length)];
btn5.setBackgroundColor(Color.RED);
}
}, 1000);
}
}
}
Example for Delay :
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Do something after 5s = 5000ms
buttons[inew][jnew].setBackgroundColor(Color.Red);
}
}, 5000);

Repeat code in android

I want an app which changes background color when pressing a button. After 500 ms, I want to change background color to black for 2000ms. And then repeat whole process again, until user terminates that.
I have following code but its not working as I think it should.
private void set() {
rl.setBackgroundColor(Color.WHITE);
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
rl.setBackgroundColor(Color.BLACK);
set(); // can I do that?
}
});
}
}, 500);
}
Can someone point me to right direction how can I do that? So I want:
Execute some code
After X time passed by , I want to execute another code and it should stay that way for X amount of time
Repeat process until user cancels that.
Something like this should work I think
Handler handler = new Handler();
Runnable turnBlack = new Runnable(){
#Override
public void run() {
myView.setBackgroundColor(Color.BLACK);
goWhite();
}};
Runnable turnWhite = new Runnable(){
#Override
public void run() {
myView.setBackgroundColor(Color.White);
goBlack();
}};
public void goBlack() {
handler.postDelayed(turnBlack, 500);
}
public void goWhite() {
handler.postDelayed(turnWhite, 2000);
}
There is much easier way to do this using AnimationDrawable:
AnimationDrawable drawable = new AnimationDrawable();
ColorDrawable color1 = new ColorDrawable(Color.YELLOW);
ColorDrawable color2 = new ColorDrawable(Color.BLACK);
// First color yellow for 500 ms
drawable.addFrame(color1, 500);
// Second color black for 2000 ms
drawable.addFrame(color2, 2000);
// Set if animation should loop. In this case yes it will
drawable.setOneShot(false);
Button btn = (Button)findViewById(R.id.button1);
btn.setBackground(drawable);
findViewById(R.id.buttonLan).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Start animation
((AnimationDrawable)v.getBackground()).start();
}
});

Categories