Android之简易音乐播放器,MediaPlayer的使用
当前实现的音乐播放器的功能有:获取本地音乐、音乐播放、暂停、歌曲切换、进度条显示、进度条控制播放位置等基本功能
主要使用了:RecyclerView显示音乐列表
MediaPlayer播放音乐
SeekBar显示进度条并控制音乐进度
ContentProvider获取本地音乐
完成后效果如下:
MainActivity.class
public class MainActivity extends AppCompatActivity implements View.OnClickListener,
SeekBar.OnSeekBarChangeListener, MediaPlayer.OnCompletionListener {
private MediaPlayer mediaPlayer;
private MusicAdapter musicAdapter;//recyclerView的适配器,用于显示音乐列表
private List musicList;
private AppCompatSeekBar seekBar;
private TextView timeStart, timeEnd;
private int mPosition = -1;//定位当前播放的音乐
private Button playB;//播放、暂停Button
@SuppressLint("HandlerLeak")
private Handler handler = new Handler(new Handler.Callback() { //在这里实现seekBar的动态更新
@Override
public boolean handleMessage(Message message) {
seekBar.setProgress(mediaPlayer.getCurrentPosition());
timeStart.setText(parseDate(mediaPlayer.getCurrentPosition()));
updateProgress();//发送更新seekBar的消息
return true;
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission();//获取权限,6.0之后读文件被设为危险权限,需要运行时请求
initView();
queryMusic();
}
private void requestPermission() {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == 1) {
if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "拒绝权限将无法正常使用程序!", Toast.LENGTH_SHORT).show();
finish();
}
}
}
@Override//退出程序时要销毁mediaPlayer
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
private void initView() {
timeStart = findViewById(R.id.time_start);
timeEnd = findViewById(R.id.time_end);
seekBar = findViewById(R.id.seek_bar);
seekBar.setOnSeekBarChangeListener(this);
playB = findViewById(R.id.music_play);
Button lastB = findViewById(R.id.last_music);
Button nextB = findViewById(R.id.next_music);
playB.setOnClickListener(this);
lastB.setOnClickListener(this);
nextB.setOnClickListener(this);
//初始化RecyclerView
final RecyclerView musicListView = findViewById(R.id.music_list);
musicList = new ArrayList<>();
musicListView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
musicAdapter = new MusicAdapter(musicList);
musicListView.setAdapter(musicAdapter);
musicAdapter.setSelected(-1);
musicAdapter.setOnItemClickListener(new MusicAdapter.OnItemClickListener() {
@Override
public void onItemClick(View v, int position) {
changeMusic(position);
mPosition = position;
}
});
musicListView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
}
private void queryMusic() {
//通过Cursor找出本地音乐文件(MP3)
Cursor cursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
if (cursor != null) {
musicList.clear();
while (cursor.moveToNext()) {
//从属性名很容易看出所代表的音乐文件属性,所以一下属性不做讲解了
String id = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
String singer = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
int time = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
int size = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));
//myMusic是我自己定义的一个javaBean,用来存放音乐文件
MyMusic myMusic = new MyMusic(id, title, singer, path, size, time, album);
musicList.add(myMusic);
}
musicAdapter.notifyDataSetChanged();
}
}
//每秒发送一个空的message,提示handler更新
private void updateProgress() {
handler.sendMessageDelayed(Message.obtain(), 1000);
}
//音乐播放
private void playMusic(MyMusic myMusic) {
try {
if (mediaPlayer == null) { //判断是否为空,避免重复创建
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnCompletionListener(this);
}
mediaPlayer.reset();//播放前重置播放器,其实第一次播放时不需要做此操作,但为了这一方法复用性我选择在这里使用
mediaPlayer.setDataSource(myMusic.getPath());//设置播放源
mediaPlayer.prepare();//准备,这一步很关键,在新播放一首歌的时候必不可少
mediaPlayer.start();//开始播放
timeEnd.setText(parseDate(mediaPlayer.getDuration()));//用来显示音乐时长
seekBar.setMax(mediaPlayer.getDuration());//设置seekBar的时长与音乐文件相同
updateProgress();//开启seekBar的更新
} catch (IOException e) {
e.printStackTrace();
}
}
private String parseDate(int time) {//cursor获取的时间是毫秒,这里将它转成常用的时间格式
time = time / 1000;
int min = time / 60;
int second = time % 60;
return min + ":" + second;
}
private void changeMusic(int position) { //实现歌曲的切换
if (position < 0) {
mPosition = musicList.size() - 1;
playMusic(musicList.get(mPosition));
} else if (position > musicList.size() - 1) {
mPosition = 0;
playMusic(musicList.get(0));
} else {
playMusic(musicList.get(position));
}
musicAdapter.setSelected(mPosition); //设置选中音乐
//更新RecyclerView,有这一步的原因是我设置了两个布局,正在播放的音乐行布局变更
musicAdapter.notifyDataSetChanged();
playB.setBackgroundResource(R.drawable.ic_playing); //更新播放、暂停键的图标
}
private void startOrPause() { //播放或暂停逻辑实现
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
playB.setBackgroundResource(R.drawable.ic_pause);
} else {
mediaPlayer.start();
playB.setBackgroundResource(R.drawable.ic_playing);
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.last_music: //上一首
changeMusic(--mPosition);
break;
case R.id.music_play: //播放/暂停
if (mediaPlayer == null) {
changeMusic(0);
} else {
startOrPause();
}
break;
case R.id.next_music://下一首
changeMusic(++mPosition);
break;
}
}
//下面三个方法是OnSeekBarChangeListener需重写的方法,此处只需重写第三个
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mediaPlayer.seekTo(seekBar.getProgress());//将音乐定位到seekBar指定的位置
updateProgress();
}
@Override
public void onCompletion(MediaPlayer mediaPlayer) { //OnCompletionListener 重写方法,实现轮播效果
changeMusic(++mPosition);
}
}
public class MusicAdapter extends RecyclerView.Adapter implements View.OnClickListener {
private int selected;
private List musicList;
private OnItemClickListener onItemClickListener;
private Context mContext;
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
mContext=parent.getContext();
View view = LayoutInflater.from(mContext).inflate(R.layout.item_music_content, parent, false);
ViewHolder holder = new ViewHolder(view);
view.setOnClickListener(this);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
MyMusic music = musicList.get(position);
holder.content.removeAllViews();
if (position==selected){
holder.content.addView(addFocusView());
TextView textView=holder.content.findViewById(R.id.music_playing);
textView.setText("正在播放:"+music.getName());
}else{
holder.content.addView(addNormalView());
TextView musicName=holder.content.findViewById(R.id.music_name);
TextView musicSinger=holder.content.findViewById(R.id.music_singer);
musicName.setText(music.getName());
musicSinger.setText(music.getSinger());
}
holder.itemView.setTag(position);
}
@Override
public int getItemCount() {
return musicList.size();
}
@Override
public void onClick(View view) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(view, (Integer) view.getTag());
}
}
class ViewHolder extends RecyclerView.ViewHolder {
RelativeLayout content;
ViewHolder(View itemView) {
super(itemView);
content=itemView.findViewById(R.id.content);
}
}
private View addFocusView(){
return LayoutInflater.from(mContext).inflate(R.layout.item_music_focus,null,false);
}
private View addNormalView(){
return LayoutInflater.from(mContext).inflate(R.layout.item_music_list,null,false);
}
public void setSelected(int selected) {
this.selected = selected;
}
public MusicAdapter(List musicList) {
this.musicList = musicList;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public interface OnItemClickListener {
void onItemClick(View v, int position);
}
}