SuperBiasedMan
SuperBiasedMan

Reputation: 9969

Editing a Button's colour in a nonUI thread (Android)

I've seen some similar questions and got some information but they stop shy of telling me enough to get it working.

What I'm trying to do is make a simple rhythm game where the player taps a button at regular intervals (ie. beats). I wanted to set up a way of signalling when to tap by having the button change colour, and since this would be a repeated task at regular intervals I want to use a timer object with a schedule method.

But when I try calling on this method it tells me that I can't change the UI in a non UI thread. I've tried a few ways to write a method in the main thread that I can call from the timer object but I get the same error every time. I'm assuming that I just have the wrong idea about what counts as being from the UI thread, so I was hoping someone could clear it up.

Here's a snippet of one way I tried it, just to show what my code looks like:

OnClickListener clickButton = new View.OnClickListener() {
public void onClick(View v) {
    if (startBeat == 0){
        startBeat = System.nanoTime();
        timerStart.scheduleAtFixedRate((new TimerTask()
        {
            public void run()
            {
                flashButton();
            }
        }), 0, beatTime);               
        timerEnd.schedule(new TimerTask()
        {
            public void run()
            {
                unflashButton();
            }
        }, beatTolerance*2, beatTime);              
        return;
    }
};

public void flashButton(){
    beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1transparent_very));
}
public void unflashButton(){
    beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1));
}

To be clear, this is all contained within my MainActivity class along with the OnCreate class.

Upvotes: 2

Views: 471

Answers (5)

yaser eftekhari
yaser eftekhari

Reputation: 235

use android.os.Handler Class. Change your code as follows:

private Handler handler=new Handler();

public void flashButton(){
    handler.post(new Runnable(){
        public void run(){
            beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1transparent_very));
        }
    });
}
public void unflashButton(){
    handler.post(new Runnable(){
        public void run(){
            beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1));
        }
    });
}

Upvotes: 0

jDur
jDur

Reputation: 1491

If you are in an Activity you could surround flashButton() with an runOnUiThread.

...
runOnUiThread(new Runnable(){
  public void run(){
      flashButton();
  }
});

...

Upvotes: 0

Panther
Panther

Reputation: 9408

UI can only be touched by the main thread. You should post the actions you are performing on the ui thread via handler or via runOnUiThread

Try something similar to this

timerStart.scheduleAtFixedRate((new TimerTask()
    {
        public void run()
        {
            //replace MainActivity with your activity
            //if inside a fragment use getActivity()
            MainActivity.this.runOnUiThread(new Runnable() {
               public void run() {
                flashButton();
               }
            });
        }
    }), 0, beatTime);    

Upvotes: 0

G. Blake Meike
G. Blake Meike

Reputation: 6715

You cannot, under any circumstances, touch a UI object from a non UI thread.

You can accomplish your intent using Handler.sendMessageDelayed

Upvotes: 0

tyczj
tyczj

Reputation: 73741

if you are in an activity all you need to do is use runOnUiThread() and then place the code to change the ui element in there

public void flashButton(){
    runOnUiThread(new Runnable() {
            @Override
            public void run() {
                beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1transparent_very));
            }
        });
}

Upvotes: 2

Related Questions