Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread not interrupting even though I'm calling thread.interrupt()

I'm learning how to use threads in Android, and to do that I've made a small application that plays a series of notes. The idea is that there is a start button and an end button and that (obviously) if you press the start button it starts playing music, and if you press the end button, it stops. The start button works just fine, but the problem is that the end button doesn't. I'm having trouble figuring out why, so maybe some of you can help me out. This is the code:

public class PressAndPlay extends Activity {
    private volatile Thread initBkgdThread;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button startButton = (Button) findViewById(R.id.trigger);
        startButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {

                // create thread
                initBkgdThread = new Thread(new Runnable() {
                    public void run() {
                        play_music();
                    }
                });
                initBkgdThread.start();
            }
        });

        Button endButton = (Button) findViewById(R.id.end);
        endButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                end_music();
            }
        });
    }

    int[] notes = {R.raw.c5, R.raw.b4, R.raw.a4, R.raw.g4};
    int NOTE_DURATION = 400;
    MediaPlayer m_mediaPlayer;

    private void play_music() {
        for(int ii=0; ii<12; ii++) {
            //check to ensure main activity is not paused
            if(!paused) {
                if (m_mediaPlayer != null) {m_mediaPlayer.release();}
                m_mediaPlayer = MediaPlayer.create(this, notes[ii%4]);
                m_mediaPlayer.start();
                try {
                    Thread.sleep(NOTE_DURATION);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void end_music() {
         if(initBkgdThread != null) {
             initBkgdThread.interrupt();
             initBkgdThread = null;
         }
    }

    boolean paused = false;
    @Override
    protected void onPause() {
        paused = true;
        super.onPause();
    }
    @Override
    protected void onResume() {
        super.onResume();
        paused = false;
    }
}
like image 999
Zero Avatar asked Mar 20 '12 16:03

Zero


People also ask

What happens when you call interrupt () on a running thread?

In Java Threads, if any thread is in sleeping or waiting state (i.e. sleep() or wait() is invoked), calling the interrupt() method on the thread, breaks out the sleeping or waiting state throwing InterruptedException.

How do you call a thread interrupt?

A thread can send an interrupt by invoking interrupt on the Thread object for the thread to be interrupted. This means interruption of a thread is caused by any other thread calling the interrupt() method. void interrupt() - Interrupts the thread.

What is the use of interrupt () function of thread class?

An interrupt is an indication to a thread that it should stop what it is doing and do something else. It's up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate.

Does thread interrupt stop thread?

interrupt() does not interrupt the thread, it continues to run.


1 Answers

You are calling interrupt() on the playing thread but it is probably waiting in sleep at the time. This will cause sleep to throw a InterruptedException. You need to catch that exception and exit the loop to stop the playing:

try {
    Thread.sleep(NOTE_DURATION);
} catch (InterruptedException e) {
    // XXX need to stop playing here, maybe return or break?
    return;
}

Since the interrupt() can also come at a different time, you need to test for interrupt status and quit your loop:

if (!paused && !Thread.currentThread().isInterrupted()) {
   ...

Also, all variables that are shared between two threads either need to be synchronized or be marked volatile. The paused flag should probably be volatile here:

volatile boolean paused = false

Lastly, for posterity, when you catch InterruptedException, it clears the interrupt status of the thread. It is usually good practice to immediately set the interrupt flag on the thread so others can test for it:

try {
    Thread.sleep(NOTE_DURATION);
} catch (InterruptedException e) {
    // re-establish the interrupt condition
    Thread.currentThread.interrupt();
    ...
}
like image 55
Gray Avatar answered Nov 15 '22 08:11

Gray