以下代码是托管MediaPlayer以从URL播放MP3流的Activity的最小示例。按" btn1"触发URL1播放(NPR播客)。按" btn2"触发URL2播放(不同电台的mp3录音)。
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();
static final String URL1 = "http://13503.mc.tritondigital.com/WAITWAIT_PODCAST/media-session/822d578a-af47-4d7e-b3ca-d18af78071bc/anon.npr-podcasts/podcast/344098539/464996449/npr_464996449.mp3";
static final String URL2 = "http://www.selbie.com/wrekapp/Fri0130.mp3";
MediaPlayer _player;
void startPlayerAsync(String url) {
stopPlayer(); // _player.reset(); _player.release(); _player=null;
Log.d(TAG, "===================");
Log.d(TAG, "Starting new player for URL: "+url);
_player = new MediaPlayer();
try
{
_player.setDataSource(url);
}
catch (IOException e) {
Log.d(TAG, "IOException", e);
return;
}
_player.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
Log.d(TAG, "onBufferingUpdate: " + percent);
}
});
_player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
if (mp == _player)
{
Log.d(TAG, "onPrepared");
_player.start();
}
}
});
_player.prepareAsync();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startPlayerAsync(URL1);
}
});
findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startPlayerAsync(URL2);
}
});
}
}
单击btn1时,听到音频之前的logspew摘要如下:
02-28 19:47:43.764 D/MainActivity: ===================
02-28 19:47:43.764 D/MainActivity: Starting new player for URL: http://13503.mc.tritondigital.com/WAITWAIT_PODCAST/media-session/822d578a-af47-4d7e-b3ca-d18af78071bc/anon.npr-podcasts/podcast/344098539/464996449/npr_464996449.mp3
02-28 19:47:44.695 1D/MainActivity: OnBufferingUpdate: 0
02-28 19:47:44.697 D/MediaPlayer: setSubtitleAnchor in MediaPlayer
02-28 19:47:44.699 D/MainActivity: onPrepared
02-28 19:47:44.703 D/MainActivity: onBufferingUpdate: 0
02-28 19:47:45.703 D/MainActivity: onBufferingUpdate: 6
02-28 19:47:46.704 D/MainActivity: onBufferingUpdate: 9
...
当为其他网址按下btn2时,行为略有不同:
02-28 19:47:18.892 D/MainActivity: ===================
02-28 19:47:18.893 D/MainActivity: Starting new player for URL: http://www.selbie.com/wrekapp/Fri0130.mp3
02-28 19:47:20.453 D/MainActivity: onBufferingUpdate: 100 <==== NOTICE THIS
02-28 19:47:20.453 D/MediaPlayer: setSubtitleAnchor in MediaPlayer
02-28 19:47:20.465 D/MainActivity: onPrepared
02-28 19:47:20.676 D/MainActivity: onBufferingUpdate: 0
02-28 19:47:21.680 D/MainActivity: onBufferingUpdate: 2
...
在第一种情况下,onBufferingUpdate(0)
之前会发生早期onPrepared
事件。然后,当流播放时,onBufferingUpdate
个调用的周期性间隔从0递增到100。
但是在第二种情况下,发生了一个虚假的onBufferingUpdate(100)
事件。但几秒钟之后,onBufferingUpdate(0)
之后的onPrepared
更正了。
用户首先点击哪个按钮或启动哪个流并不重要。我甚至将URL2的mp3文件从其原始服务器移动到另一台服务器。有关于第二个URL的mp3流导致MediaPlayer想要以这种方式运行的东西。在我的实际应用中,这会导致&#34;二次进展&#34;我的进度控制线在显示预期缓冲之前显示实线一秒。这是应用程序的视觉瑕疵。
我的解决方法是在onBufferingUpdate
被触发之前忽略所有onPrepared
个事件。在我做出改变之前,我想了解一下为什么会发生这种情况。并确保可以安全地假设在流启动之前缓冲达到100%是不合法的。这是正确的解决办法吗?
答案 0 :(得分:0)
没有其他选项,当MediaPlayer处于准备状态并且之前没有使用非零值调用时,我决定忽略对onBufferingUpdate的任何调用,其值为100 :
实际上,代码变为:
_player.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
// percent can be something awkward like "-2147483648" on a live source. Just clamp it.
if (percent < 0) {
percent = 0;
}
else if (percent > 100) {
percent = 100;
}
if ((_state == Preparing) && (_secondaryPercent == 0) && (percent == 100)) {
Log.d(TAG, "onBufferingUpdate(100) invoked while in preparing state - ignoring");
}
else if (_secondaryPercent != percent) {
_secondaryPercent = percent;
handleBufferingUpdate(percent);
}
}
});