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<MyMusic> 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); } }
MusicAdapter.class
public class MusicAdapter extends RecyclerView.Adapter<MusicAdapter.ViewHolder> implements View.OnClickListener { private int selected; private List<MyMusic> 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<MyMusic> musicList) { this.musicList = musicList; } public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } public interface OnItemClickListener { void onItemClick(View v, int position); } }