1

I'm having a hard time working with this.

I have a Media player, and I can play, pause, stop, play again after pause, stop... whatever. Now I wanted to have a SeekBar to give a visual component. My problem is: When I start the player for the first time everything works well. Music plays, and seek bar updates. also works when I pause.

Now, if I stop the player and start it again, the player starts, the run() method executes, but the seekbar doesn't update, and soon the app gives a not responging error. What am I missing here?

The run method is an implementation from the Runnable interface, and with a simple log, I can see it's being executed, even after the stop/play case. The only thing that seems not to be working is the seek.setProgress(...). some help, please? :)

Here's my code:

public class MediaPlayerTestingActivity extends Activity 
               implements OnClickListener, OnPreparedListener, Runnable {

private MediaPlayer mp;
private boolean paused = false;
private SeekBar seek;
private boolean threadStarted = false;;
private Thread thread = new Thread(this);


/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    seek = (SeekBar)findViewById(R.id.seek);
    mp = new MediaPlayer();

    Button start = (Button)findViewById(R.id.start);
    start.setOnClickListener(this);
    Button pause = (Button)findViewById(R.id.pause);
    pause.setOnClickListener(this);
    Button stop = (Button)findViewById(R.id.stop);
    stop.setOnClickListener(this);

}

//click handlers
public void onClick(View v) 
{
    int buttonId = v.getId();

    switch (buttonId)
    {
        case R.id.start:
            if(mp != null)
            {
                if(!mp.isPlaying() && !paused)
                    prepareTostartPlayer();
                else
                    mp.start(); //if it was just paused
            }
            else
            {
                mp = new MediaPlayer();
                prepareTostartPlayer();
            }
            break;
        case R.id.pause:
            if(mp.!= null && mp.isPlaying())
            {   
                mp.pause();
                paused = true;
            }
            break;

        case R.id.stop:
            if(mp != null && mp.isPlaying())
            {
                mp.stop();
                mp.release();
                mp = null;
            }
            break;

        default:
            break;
    }
}

//When the player is ready to play
public void onPrepared(MediaPlayer arg0) 
{
    seek.setMax(mp.getDuration());
    mp.start(); 
    if(!threadStarted)
        thread.start();
    else
        thread.run();
}

//Method to prepare to start the player
private void prepareTostartPlayer()
{
    mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
    try {
        mp.setDataSource("http://feedproxy.google.com/~r/rc-cadernetadecromos/~3/JH1kfZCmP3M/cdc_190112_2.mp3");
        mp.prepareAsync();
        mp.setOnPreparedListener(this);
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void run() 
{
    threadStarted   = true;
    int current = 0;
    while(mp != null && current < mp.getDuration())
    {
        try {
            current = mp.getCurrentPosition();
            seek.setProgress(current);
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }       
}

}

Tudor
  • 61,523
  • 12
  • 102
  • 142
Nuno Gonçalves
  • 6,202
  • 7
  • 46
  • 66
  • "but the seekbar doesn't update" - what do you mean by this? – Gangnus Jan 21 '12 at 13:30
  • The seekbar progress doesn't update. – Nuno Gonçalves Jan 21 '12 at 13:53
  • But if it was paused, it should be on the same place, so, what update do you need? --- And read my answer - threads in Android almost don't work at all. – Gangnus Jan 21 '12 at 14:00
  • When I stop the music, I want to be able to restart it. It would be a limitation not being able to stop/restart an audio file. – Nuno Gonçalves Jan 21 '12 at 14:03
  • stop/pause/restart/resume - which doesn't work? Seekbar progress is a little thingie placed on the progress bar. You said it is not updated. How that is connected with restarting or not restarting. It seems, you have more, than one problem. Write all of them down, one by one. Don't mix them. Better try to put in different questuins. Manage them one by one, too, not all simultaneously. And, friend, if you can't explain the problem to me, don't think you'll explain it to the comp - maybe I am not so smart, but it is even less smart. – Gangnus Jan 21 '12 at 14:10

2 Answers2

0

I see three issues here:

First, this part:

public void onPrepared(MediaPlayer arg0) 
{
    seek.setMax(mp.getDuration());
    mp.start(); 
    if(!threadStarted)
        thread.start();
    else
        thread.run();
}

The first time your run the thread you set threadStarted to true in the thread code, but you never set it back to false when the thread finishes. So after the first run it will be true forever and thus the else above will always execute, running the player code sequentially and thus blocking your user interface.

Second, you are updating the user interface (the SeekBar) from a different thread than the UI thread. See this related question for how to correctly update the UI in this case: Update UI from Thread

Third, this may be just a recommendation, but since your threadStarted variable is modified between threads, it's better to declare it volatile to prevent some optimizations from breaking your code:

private volatile boolean threadStarted = false;
Community
  • 1
  • 1
Tudor
  • 61,523
  • 12
  • 102
  • 142
  • But the problem is that I can't start thread after it has been started before. I get a java.lang.IllegalThreadStateException: Thread already started Even after it ended. That's why I placed that condition there, and hoped the thread.run() would do it. – Nuno Gonçalves Jan 21 '12 at 12:38
  • @Nuno Gonçalves: Where is the code that is supposed to stop the thread? You should call thread.interrupt() and then in the catch of the InterruptedException set threadStarted to false and use return to exit. – Tudor Jan 21 '12 at 12:42
  • The method "thread.stop()" is depracated for security issues. There's not way I can figure to stop the thread. http://developer.android.com/reference/java/lang/Thread.html#stop%28java.lang.Throwable%29 – Nuno Gonçalves Jan 21 '12 at 12:45
  • Concerning your second issue, I was using a Handler before, and the result was the same. I just found this approach on the web and tryed it. When I get this working, I'll get back at that approach. – Nuno Gonçalves Jan 21 '12 at 12:48
  • "thread.interrupt();" i also tried that. But I'll get the same exception, "thread already started". – Nuno Gonçalves Jan 21 '12 at 12:54
  • But have you put { threadStarted = false; return; } in the InterruptedException catch block? – Tudor Jan 21 '12 at 13:01
  • Yes, and the result is the same. Either that, or i'm doing something wrong. – Nuno Gonçalves Jan 21 '12 at 13:09
  • Hmm. Try to put another member in the class volatile boolean shouldRun = true; Then test that value in the while loop of the thread along with the other conditions. Then when you need to exit set the variable to false; – Tudor Jan 21 '12 at 13:12
  • Same thing... and it's making me craaaazy. :) – Nuno Gonçalves Jan 21 '12 at 13:33
  • Please update your original question with the code you tried now. – Tudor Jan 21 '12 at 13:36
  • I just made something, but I'm not sure if it's a good practice. It works though. I set the thread to null when I click stop. Then when I call "play" if the thread is null, I create a new one. I'm not sure if this is a good approoach and if the thread resources are actually freed or not. – Nuno Gonçalves Jan 21 '12 at 13:40
  • @Nuno Gonçalves: You are not stopping the thread that way. You are simply making the reference point to another thread, but the old thread will keep running. – Tudor Jan 21 '12 at 13:44
-1

According to my experience and what is written in docs, threads in Android work only in purely algorythmic parts of a prog. Any try to use them in activities, or anything connected to UI, goes to error. This way it simply won't work. Never can you repair it!

Use AsyncTask (or child Activity/Fragment for greater things) instead.

Gangnus
  • 24,044
  • 16
  • 90
  • 149