【问题标题】:Android Media Player Seek bar not updating on start after stopAndroid Media Player 搜索栏在停止后启动时不更新
【发布时间】:2012-01-21 11:36:55
【问题描述】:

我很难处理这个问题。

我有一个媒体播放器,我可以播放、暂停、停止、暂停后再次播放、停止……等等。 现在我想要一个 SeekBar 来提供一个视觉组件。我的问题是: 当我第一次启动播放器时,一切正常。音乐播放,并寻求酒吧更新。当我暂停时也有效。

现在,如果我停止播放器并重新启动它,播放器就会启动,run() 方法会执行,但 seekbar 不会更新,很快应用就会出现无响应错误。 我在这里想念什么?

run 方法是 Runnable 接口的一个实现,通过一个简单的日志,我可以看到它正在执行,即使在停止/播放情况之后也是如此。唯一似乎不起作用的是 seek.setProgress(...)。 请帮忙? :)

这是我的代码:

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();
        }
    }       
}

}

【问题讨论】:

  • “但是搜索栏没有更新”——这是什么意思?
  • 搜索栏进度不更新。
  • 但是如果它被暂停了,它应该在同一个地方,那么,你需要什么更新? --- 并阅读我的答案 - Android 中的线程几乎根本不起作用。
  • 当我停止播放音乐时,我希望能够重新启动它。无法停止/重新启动音频文件将是一个限制。
  • 停止/暂停/重启/恢复 - 哪个不起作用? Seekbar 进度是放置在进度条上的一个小东西。你说没有更新。这与重新启动或不重新启动有什么关系。看来,您的问题不止一个。把它们都一一写下来。不要混合它们。最好尝试放入不同的questuins。也一一管理它们,而不是同时管理它们。而且,朋友,如果你不能向我解释这个问题,不要以为你会向比赛解释——也许我没有那么聪明,但它更不聪明。

标签: java android multithreading seekbar android-mediaplayer


【解决方案1】:

我在这里看到三个问题:

首先,这部分:

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

第一次运行线程时,您在线程代码中将threadStarted 设置为true,但在线程完成时您从未将其设置回false。因此,在第一次运行之后,它将永远是true,因此上面的else 将始终执行,依次运行播放器代码,从而阻塞您的用户界面。

第二,您正在从与 UI 线程不同的线程更新用户界面(SeekBar)。有关在这种情况下如何正确更新 UI,请参阅此相关问题:Update UI from Thread

第三,这可能只是一个建议,但由于你的threadStarted变量是在线程之间修改的,最好声明为volatile,以防止某些优化破坏你的代码:

private volatile boolean threadStarted = false;

【讨论】:

  • 但问题是之前启动过的线程我无法启动。我得到一个 java.lang.IllegalThreadStateException: Thread already started 即使它结束了。这就是为什么我把这个条件放在那里,并希望 thread.run() 能做到。
  • @Nuno Gonçalves:应该停止线程的代码在哪里?您应该调用 thread.interrupt() 然后在 InterruptedException 的捕获中将 threadStarted 设置为 false 并使用 return 退出。
  • 由于安全问题,方法“thread.stop()”已弃用。我无法停止线程。 developer.android.com/reference/java/lang/…
  • 关于你的第二个问题,我之前用的是Handler,结果是一样的。我刚刚在网上找到了这种方法并尝试了它。当我得到这个工作时,我会回到那个方法。
  • "thread.interrupt();"我也试过了。但我会得到同样的例外,“线程已经启动”。
【解决方案2】:

根据我的经验和docs 中所写的内容,Android 中的线程仅在 prog 的纯算法部分中工作。任何尝试在活动中使用它们,或任何连接到 UI 的东西,都会出错。这种方式根本行不通。 永远你不能修复它!

改用 AsyncTask(或子 Activity/Fragment 做更多事情)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多