2. 使用MediaPlayer播放网络音频
任务说明
本案例将实现一个最小可用的网络音频播放器:界面包含播放/暂停按钮、进度条和状态提示文本,核心逻辑使用 MediaPlayer 播放远程 MP3 文件,并处理缓冲等待与错误状态。你需要准备一个可访问的 MP3 直链用于测试。
核心实现
首先在 AndroidManifest.xml 中声明网络权限:
<uses-permission android:name="android.permission.INTERNET" />
布局文件 activity_main.xml 包含三个核心控件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="24dp">
<Button
android:id="@+id/btnPlayPause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播放" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:max="100" />
<TextView
android:id="@+id/tvStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="就绪" />
</LinearLayout>
主活动 MainActivity.java 中完成 MediaPlayer 的创建、状态监听与界面更新:
package com.example.netaudio;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private MediaPlayer mediaPlayer;
private Button btnPlayPause;
private ProgressBar progressBar;
private TextView tvStatus;
private Handler handler = new Handler();
private boolean isPlaying = false;
private static final String AUDIO_URL =
"https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3";
private Runnable progressRunnable = new Runnable() {
@Override
public void run() {
if (mediaPlayer != null && isPlaying) {
int current = mediaPlayer.getCurrentPosition();
int duration = mediaPlayer.getDuration();
if (duration > 0) {
progressBar.setProgress(current * 100 / duration);
}
handler.postDelayed(this, 500);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnPlayPause = findViewById(R.id.btnPlayPause);
progressBar = findViewById(R.id.progressBar);
tvStatus = findViewById(R.id.tvStatus);
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(mp -> {
tvStatus.setText("缓冲完成,开始播放");
mp.start();
isPlaying = true;
btnPlayPause.setText("暂停");
handler.post(progressRunnable);
});
mediaPlayer.setOnBufferingUpdateListener((mp, percent) -> {
// percent 表示缓冲百分比,可用于显示缓冲进度
if (!isPlaying) {
tvStatus.setText("缓冲中:" + percent + "%");
}
});
mediaPlayer.setOnErrorListener((mp, what, extra) -> {
tvStatus.setText("播放错误,请检查网络或URL");
isPlaying = false;
btnPlayPause.setText("播放");
return true;
});
mediaPlayer.setOnCompletionListener(mp -> {
tvStatus.setText("播放完成");
isPlaying = false;
btnPlayPause.setText("重新播放");
progressBar.setProgress(100);
});
btnPlayPause.setOnClickListener(v -> {
if (!isPlaying) {
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(AUDIO_URL);
mediaPlayer.prepareAsync();
tvStatus.setText("正在缓冲...");
btnPlayPause.setEnabled(false);
} catch (Exception e) {
tvStatus.setText("初始化失败:" + e.getMessage());
}
} else {
mediaPlayer.pause();
isPlaying = false;
btnPlayPause.setText("继续");
handler.removeCallbacks(progressRunnable);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacks(progressRunnable);
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
}
}
关键逻辑说明
- 缓冲处理:调用
prepareAsync()异步准备,通过setOnPreparedListener获知缓冲完成;setOnBufferingUpdateListener实时获取缓冲百分比并更新状态文本。 - 错误处理:
setOnErrorListener捕获网络异常、URL 无效等错误,重置界面状态并提示用户。 - 进度更新:使用
Handler每 500ms 查询播放位置并更新进度条,暂停或销毁时移除回调。
验证方法
将项目部署到 Android 设备或模拟器(需联网),点击“播放”按钮。预期观察:
- 状态文本先显示“正在缓冲...”,随后出现“缓冲中:xx%”,最终变为“缓冲完成,开始播放”;
- 进度条随播放推进,按钮文字变为“暂停”;
- 点击“暂停”后进度条停止,按钮变为“继续”;点击“继续”恢复播放;
- 断开网络后重新播放,状态文本应显示“播放错误,请检查网络或URL”,界面不崩溃。
若以上行为均符合,则案例验证通过。注意:首次播放需等待缓冲完成,实际耗时取决于网络状况。