0

I am starting a thread when invoking a method to play an audio file.

The code runs ok the first time but when I call the play method again I need the thread to start as if it were being called the first time. I have tried to interrupt the thread and even stop it but nothing seems to work.

How can I properly restart the thread?

Here is some code to help explain.

Global variable

private Thread thread1;

Thread code:

thread1 = new Thread(new Runnable() 
    {
        @Override
         public void run() 
        {
             try {
             int i=0;

             final TextView timeDuration = (TextView) findViewById(R.id.timeDisplay);
             final SeekBar seekBar = (SeekBar)findViewById(R.id.seekBar1);
             while (running)
             {
                info();
                j = 0;
                while(i>0 && running)
                {


                while(j<duration && running && (playStatus.getValue() == "TRANSITIONING" ||         playStatus.getValue() == "PLAYING"))
                {

                seekBar.setMax((int) duration);
                seekBar.setProgress(0);

                runOnUiThread(new Runnable() 
                { 
                                    public void run() 
                                    {
                                        System.out.println("PLAYBACK STATUS: "+playStatus.getValue());
                                        timeDuration.setText(""+(j+1));
                                        seekBar.setProgress(j+1);
                                            if(j==(duration-1))
                                        {
                                            setRunning(false);
                                        }

                                    }
                });
                Thread.sleep(1 * 1000);
                j++;
                if(seekBar.getProgress() == seekBar.getMax())
                {

                runOnUiThread(new Runnable() 
                    { 
                                        public void run() 
                                        {
                                            playButton.setVisibility(View.VISIBLE);
                                            pauseButton.setVisibility(View.GONE);
                                            timeDuration.setText(""+"0");
                                            seekBar.setProgress(0);
                                            flag = false;
                                            System.out.println("J VALUE 1: = "+j);
                                            duration = 0;
                                            setRunning(false); 
                                        }
                    });
                }

                }
                }

                j = 0;
                        i++;
                        Thread.sleep(1 * 1000);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
         }
    });

    play();

This code works fine and plays the track. It then resets the seekbar and awaits for the play method to be called again.

public void play()
{

    try 
    { 

        thread1.start();
    } 
    catch(Exception e) 
    { 
            return; 
    }

}

Here is the setRunning method recommended to me.

public void setRunning(boolean b)
{
      this.running = b;
}

If anyone know of a solution to this problem I would really appreciate it.

phant0m
  • 16,595
  • 5
  • 50
  • 82

3 Answers3

1

Threads are not supposed to be stopped manually. You should use a boolean instead of true in your while loop, and put the boolean to false through a setter when you want to stop:

private boolean running;

@Override
public void run(){
  running = true;
  while(running) {...}
}

public void setRunning(boolean b){
  this.running = b;
}
JoxTraex
  • 13,423
  • 6
  • 32
  • 45
kgautron
  • 7,915
  • 9
  • 39
  • 60
  • 1
    Log the state of running in the loop to make sure its being changed. And theres a bug in setRunning, the line should be this.running=b; not false. – Nick Aug 03 '12 at 20:26
  • I tried this change and it still didn't work. I tried to set the state of running to false after 3 seconds but the loop kept running. – Dark Knight Rising Aug 04 '12 at 08:39
  • Have you put the boolean in the condition of the second while loop too? because it seems the second loop does not stop until the end of the track. – kgautron Aug 04 '12 at 08:50
  • Yeah I put the boolean condition in the second and third while loop. I can now exit the loop after 3 seconds if I change the boolean state. It looks like I have exit from the thread but the problem now is that I can't seem to start the thread again when I call the play() method. – Dark Knight Rising Aug 04 '12 at 09:51
  • The condition in the third loop is not right, the || at the end will make the loop keep running even if the boolean is false because you did not use parenthesis so your boolean operators are executed from left to right. Do something like while(running && (rest of conditions)). You can remove the boolean from the other loops. – kgautron Aug 04 '12 at 10:23
  • I've tried this: while(running && (j – Dark Knight Rising Aug 04 '12 at 10:50
  • Once the thread has finished his execution it is probably disposed of, so just start a new one. – kgautron Aug 04 '12 at 11:10
  • That's what I'm trying to do by running the play() method for a second time which is supposed to start thread1 again. Is there a problem with trying to start a thread for a second time after it has finished it's first run? – Dark Knight Rising Aug 04 '12 at 11:31
  • As I said you probably can't reuse your original thread once it has finished. Call new Thread() in the play method so that a new instance is used every time. – kgautron Aug 04 '12 at 11:39
  • Thanks KayKay. You're a legend :) – Dark Knight Rising Aug 04 '12 at 13:37
0

To restart your player you need to prepare again.

    public void restartAudio() {
        Log.e(TAG, "restartAudio");
        if (mp.isPlaying()) {
            mp.seekTo(0);
        }else{
            mp.stop();
            try {
                mp.prepare();
            } catch (IllegalStateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
Nick
  • 1,340
  • 1
  • 15
  • 23
0

When using extra boolean flag to controll thread's while loop don't forget to use volatile modifier on it:

     private volatile boolean running;

or put appropriate synchronization.

Apart from that, I'd think about using Thread.isInterrupted() method instead of the additional 'running' flag: http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#isInterrupted()

here's why: https://stackoverflow.com/a/3196058/1350225

Community
  • 1
  • 1