Android之简易音乐播放器,MediaPlayer的使用

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);
    }
}

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值