我的应用程序允许用户从多个音频流中进行选择,当用户点击其中一个播放按钮时,将调用以下代码:
@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;
}
有关如何修复此问题或以某种方式取消先前音频的准备的任何想法?
答案 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);
。