"在断开连接的媒体播放器上回调"重用MediaPlayer时

时间:2014-03-12 19:36:41

标签: android android-mediaplayer

我的应用程序允许用户从多个音频流中进行选择,当用户点击其中一个播放按钮时,将调用以下代码:

@Override
public void onClick(View view)
{
    mMediaPlayer.reset();
    mMediaPlayer.setOnCompletionListener(this);
    mMediaPlayer.setOnErrorListener(this);
    mMediaPlayer.setOnBufferingUpdateListener(this);
    try
    {
        mMediaPlayer.setDataSource(mSelected.getUrl());
        mMediaPlayer.prepareAsync();
    }
    catch (Exception e)
    {
        Toast.makeText(mActivity, R.string.error_media, Toast.LENGTH_LONG).show();
    }
}

然后是onPrepared监听器:

@Override
public void onPrepared(MediaPlayer mp)
{
    mHandler.post(new Runnable()
    {
        @Override
        public void run()
        {
            mPlayer.start();
        }
    });
}

这主要有用,但有时当用户点击其中一个播放按钮而前一个仍在准备时,我收到错误MEDIA_ERROR_IO错误(1,-1004)。查看调试日志,我看到消息callback on disconnected mediaplayer意味着它可能正在尝试调用onPrepared,但我认为MediaPlayer已经被重置。 OnError侦听器被称为:

@Override
public boolean onError(MediaPlayer mp, int what, int extra)
{
    Toast.makeText(this, "error", Toast.LENGTH_SHORT).show();
    return true;
}

有关如何修复此问题或以某种方式取消先前音频的准备的任何想法?

2 个答案:

答案 0 :(得分:2)

好的,所以在经过几周的讨论之后我发现你无法使用一个MediaPlayer个实例来处理多个文件,因为你无法取消prepareAsync()操作。如果您reset()release()为了在第一个音频文件准备时播放第二个音频文件,那么当第一个准备操作尝试回调时,它会发现MediaPlayer已经断开连接并发出MEDIA_ERROR_IO错误。

所以我所做的是将一个不同的MediaPlayer实例与我的每个播放按钮相关联。我还跟踪了每个MediaPlayer实例的状态(重置,准备或准备)。这是代码:

<强> MyActivity.java

// Listener for every play button
@Override
public void onClick(View view)
{
    for (AudioItem item : mAudioItems)
    {
        if (item.getPlayButton().equals(view))
        {
            mCurrentAudio = item;
        }
        else
        {
            resetAudio(item);
        }
    }

    if (mCurrentAudio.getStatus() == MediaStatus.STOPPED)
    {
        MediaPlayer player = mCurrentAudio.getMediaPlayer();
        try
        {
            player.setDataSource(mCurrentAudio.getUrl());
            mCurrentAudio.setStatus(MediaStatus.PREPARING);
            player.prepareAsync();
        }
        catch (Exception e)
        {
            for (AudioItem item : mAudioItems)
            {
                resetAudio(item);
            }
        }
    }
    else if (mCurrentAudio.getStatus() == MediaStatus.PREPARED)
    {
        // toggle play/pause
    }
}

@Override
public void onPrepared(MediaPlayer mp)
{
    if (!mCurrentAudio.getMediaPlayer().equals(mp))
    {
        for (AudioItem item : mAudioItems)
        {
            if (item.getMediaPlayer().equals(mp))
            {
                item.setStatus(MediaStatus.PREPARED);
                resetAudio(item);
                return;
            }
        }
    }

    mCurrentAudio.setStatus(MediaStatus.PREPARED);

    // play audio
}

public void resetAudio(AudioItem item)
{
    if (item.getStatus() != MediaStatus.PREPARING)
    {
        item.getMediaPlayer().reset();
        item.setStatus(MediaStatus.STOPPED);
    }
}

<强> AudioItem.java

public class AudioItem
{
    private MediaPlayer mMediaPlayer;
    private ImageButton mPlayButton;
    private String      mUrl;
    private int         mStatus;

    public AudioItem(MediaPlayer player, ImageButton button, String url)
    {
        mMediaPlayer = player;
        mPlayButton = button;
        mUrl = url;
        mStatus = MediaStatus.STOPPED;
    }

    // getters and setters
}

答案 1 :(得分:2)

与此相关但不是确切的情况,当我在调用V/MediaPlayer[Native]﹕ notify(8, 0, 0) callback on disconnected mediaplayer之前尝试播放视频时,我在日志中看到了相同的setSurface(.)错误。我无意中从未调用它,因为只有当我的TextureView可用时才设置它(SurfaceTextureListener#onSurfaceTextureAvailable(.)),这只有在视图的可见性为VISIBLE时才会发生!因此,我的根本修复是确保在正确的时间调用mTextureView.setVisibility(View.VISIBLE);