tags:

views:

34

answers:

1

I have a Image button which doubles as a play and stop button. I need the image in the button to change when the user click on it the first time, so that it now looks like a stop button. But this won't happen till the thread completes playing the song.

ImageButton Sound;
public void onClick(View v) {
    selectRandomSong();
    Sound.setBackgroundResource(R.drawable.stop);
    v.invalidate();
    if(playing)
        stop();
    else
        play();
    Sound.setBackgroundResource(R.drawable.play);
}

setBackground wont reflect on the view as the invalidation does not occur. Where and how should I invalidate this?

A: 

I'm not sure how stop() and play() are implemented, but based on your description it sounds like they block the UI thread so that the button background is never changed. Running those functions in a separate thread would solve the blocking issue, but you are only allowed to update the background resource on the UI thread. In order to get around that problem, you can use the Activity.runOnUiThread() call.

This code isn't thread-safe (and it's untested), but should give you a good starting point.

ImageButton Sound;
public void onClick(View v) {

    //Kick off a new thread to play the song without blocking the UI thread
    Thread playSongThread = new Thread() {
        public void run() {
            selectRandomSong();
            setBackgroundResource(R.drawable.stop);
            //v.invalidate(); //shouldn't be neccessary
            if(playing)
                stop();
            else
                play();
            setBackgroundResource(R.drawable.play);
        }       
    };      
    playSongThread.start();
}

/**
 * Sets the background resource using the UI thread
 * @param id Resource ID to set the background to
 */
private void setBackgroundResource(final int id)
{
    this.runOnUiThread(new Runnable()
    {
        public void run()
        {
            Sound.setBackgroundResource(id);                
        }
    });
}
Aaron C
You nailed it!!! It works like a charm ... but can you please elaborate why this code is thread unsafe?
Arvind
Because this is multi-threaded, it is possible for one thread to make a decision based on the "playing" boolean just before another thread changes that boolean. Because of this, you might see odd behavior if the user presses the button several times in quick succession.
Aaron C