简易音乐播放器的制作

一.作业目标

实现简单的音乐播放以及切歌功能(只包含一个主界面与一个底部控制台用于切换歌曲)

二.实现步骤

我们实现音乐播放器的流程分为四步:

1.绘制音乐播放器的布局,其中包括主界面音乐列表与列表中每个item的绘制

2.音乐播放器的音频文件获取,这部分要实现对本地音频的获取与传送,并将其展现出来

3.实现在点击RecylceView中item能播放和切换歌曲功能

4.对底部控件进行设置,关联相关操作,以此实现播放暂停音乐,跳转上一曲,下一曲功能

将四个部分完成,即可实现简易的音乐播放器功。

三.关键代码解析以及技术说明

在整个音乐播放器的制作过程中,我们需要首先需要利用到RecycleView在主界面将我们的歌曲列表视图展现出来,这部分,我们还需要设置一个适配器,这里我们采用RecycleView中的Adapter类来完成,将其命名为LocalMusicAdapter。然后需要利用到CardView将每一首歌曲信息以列表元素的形式展现出来,我们在此部分需要对我们想要展现的数据进行传递,还需要对布局进行规划,将其展现在item的合适位置,LocalMusicBean类用于封装每首音乐的信息,并且在加载本地音乐数据时创建LocalMusicBean对象,将其添加到mDatas列表中。。在底部部分,则需要制作一个可以控制音乐播放,暂停,上一曲,下一曲的控制台,这部分需要在对应位置插入图片,并对Button的功能进行监听器设置。至于音乐文件,我们采取读取本地内存中的音乐,利用ContenResolver实现对本地音频内容的访问并接受获取到的音乐文件,然后将其展现在RecycleView中,。最后是音乐的播放部分,我们使用MeidaPlayer来完成

本地音频获取:

SD卡访问权限设置

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  xml设计:

歌曲信息xml设计

提前准备的控制button:

接下来我们着手编写程序主体部分

LocalMusciAdapter

 @Override
    public void onBindViewHolder(@NonNull LocalMusicViewHolder holder, final int position) {
        LocalMusicBean musicBean = mDatas.get(position);
        holder.idTv.setText(musicBean.getId());
        holder.songTv.setText(musicBean.getSong());
        holder.singerTv.setText(musicBean.getSinger());
        holder.albumTv.setText(musicBean.getAlbum());
        holder.timeTv.setText(musicBean.getDuration());

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int currentPosition = holder.getAdapterPosition();
                onItemClickListener.OnItemClick(v, currentPosition);
            }
        });
    }

在onBindViewHolder方法中,我们实现的功能是将音乐数据和对应的视图内容进行绑定,并为每个列表项设置点击监听器,以便响应用户的点击操作将数据项与视图进行绑定,即将本地音乐列表中每个音乐的数据填充到对应的文本视图中。首先获取当前位置position的音乐数据项,然后将其对应的各个属性设置到LocalMusicViewHolder实例的相应成员变量中,即设置显示在列表项中的文本内容。接着,通过设置holder.itemView的点击监听器,实现了当用户点击某个本地音乐列表项时的响应操作。

  protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        mediaPlayer = new MediaPlayer();
        mDatas = new ArrayList<>();
//     创建适配器对象
        adapter = new LocalMusicAdapter(this, mDatas);
        musicRv.setAdapter(adapter);
//        设置布局管理器
        LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        musicRv.setLayoutManager(layoutManager);
//        加载本地数据源
        loadLocalMusicData();
//        设置每一项的点击事件
        setEventListener();
    }

在Mainactivity中初始化主活动的布局和视图,创建适配器并与RecyclerView关联,设置布局管理器,加载本地音乐数据,并为每一项设置点击事件。

 private void loadLocalMusicData() {
        /* 加载本地存储当中的音乐mp3文件到集合当中*/
        ContentResolver resolver = getContentResolver();
//        2.获取本地音乐存储的Uri地址
        Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        Cursor cursor = resolver.query(uri, null, null, null, null);
//        4.遍历Cursor
        int id = 0;
        while (cursor.moveToNext()) {
            int titleIndex = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
            int artistIndex = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
            int albumIndex = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);
            int dataIndex = cursor.getColumnIndex(MediaStore.Audio.Media.DATA);
            int durationIndex = cursor.getColumnIndex(MediaStore.Audio.Media.DURATION);
            int albumIdIndex = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID);
            if (titleIndex >= 0 && artistIndex >= 0 && albumIndex >= 0 && dataIndex >= 0 && durationIndex >= 0 && albumIdIndex >= 0) {
                String song = cursor.getString(titleIndex);
                String singer = cursor.getString(artistIndex);
                String album = cursor.getString(albumIndex);
                id++;
                String sid = String.valueOf(id);
                String path = cursor.getString(dataIndex);
                long duration = cursor.getLong(durationIndex);
                SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
                String time = sdf.format(new Date(duration));
                String album_id = cursor.getString(albumIdIndex);
                String albumArt = getAlbumArt(album_id);
                LocalMusicBean bean = new LocalMusicBean(sid, song, singer, album, time, path,albumArt);
                mDatas.add(bean);
            } else {
                // 处理列不存在的情况
            }
        }
//        数据源变化,提示适配器更新
        adapter.notifyDataSetChanged();
    }

加载本地音乐的方法loadLocalMusicdata

利用ContentResolver对象获取本地音乐存储uri地址,然后使用query()方法查询Uri所代表的数据,返回一个Cursor对象用于遍历查询结果,获取其中的信息,并封装到LocalMusicBean对象中。

 此时,我们已经完成了对内存音频文件的获取与展示,接下来就是音频播放部分:

在Adapterd的onBindView中给ViewHolder的整个itemView设置点击事件

  holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int currentPosition = holder.getAdapterPosition();
                onItemClickListener.OnItemClick(v, currentPosition);
            }
        });

为RecyclerView的每个item设置点击事件,并在点击时更新当前播放位置,并根据点击位置播放对应的音乐

    private void setEventListener() {
        /* 设置每一项的点击事件*/
        adapter.setOnItemClickListener(new LocalMusicAdapter.OnItemClickListener() {
            @Override
            public void OnItemClick(View view, int position) {
                currnetPlayPosition = position;
                LocalMusicBean musicBean = mDatas.get(position);
                playMusicInMusicBean(musicBean);
            }
        });
    }

接下来是播放与暂停音乐的函数playMusic

mediaPlayer!=null&&!mediaPlayer.isPlaying()用来确定MediaPlayer对象不为空且当前没有正在播放的音乐

然后,在判断currentPausePositionInSong是否为0的条件下进行不同的操作

 public void playMusicInMusicBean(LocalMusicBean musicBean) {
        /*根据传入对象播放音乐*/
        //设置底部显示的歌手名称和歌曲名
        singerTv.setText(musicBean.getSinger());
        songTv.setText(musicBean.getSong());
        stopMusic();
//                重置多媒体播放器
        mediaPlayer.reset();
//                设置新的播放路径
        try {
            mediaPlayer.setDataSource(musicBean.getPath());
            String albumArt = musicBean.getAlbumArt();
            Log.i("lsh123", "playMusicInMusicBean: albumpath=="+albumArt);
            Bitmap bm = BitmapFactory.decodeFile(albumArt);
            Log.i("lsh123", "playMusicInMusicBean: bm=="+bm);
            albumIv.setImageBitmap(bm);
            playMusic();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

停止音乐函数:

private void stopMusic() {
        /* 停止音乐的函数*/
        if (mediaPlayer!=null) {
            currentPausePositionInSong = 0;
            mediaPlayer.pause();
            mediaPlayer.seekTo(0);
            mediaPlayer.stop();
            playIv.setImageResource(R.mipmap.icon_play);
        }

    }

到此,点击item即可播放音乐,接下来我们要实现的是底部按钮功能,实现对点击事件的监听,根据按钮实现播放,暂停,上一曲,下一曲功能。

暂停:

   private void pauseMusic() {
        /* 暂停音乐的函数*/
        if (mediaPlayer!=null&&mediaPlayer.isPlaying()) {
            currentPausePositionInSong = mediaPlayer.getCurrentPosition();
            mediaPlayer.pause();
            playIv.setImageResource(R.mipmap.icon_play);
        }
    }

最后一部分控制上一曲与下一曲的功能代码,通过将播放位置进行加一减一操作,进而控制歌曲播放位置,分别对三个button进行了不同功能调用,从而实现了切歌功能。

   public void onClick(View v) {
        int viewId = v.getId();
        if (viewId == R.id.local_music_bottom_iv_last) {
            if (currnetPlayPosition == 0) {
                Toast.makeText(this, "已经是第一首了,没有上一曲!", Toast.LENGTH_SHORT).show();
                return;
            }
            currnetPlayPosition = currnetPlayPosition - 1;
            LocalMusicBean lastBean = mDatas.get(currnetPlayPosition);
            playMusicInMusicBean(lastBean);
        } else if (viewId == R.id.local_music_bottom_iv_next) {
            if (currnetPlayPosition == mDatas.size() - 1) {
                Toast.makeText(this, "已经是最后一首了,没有下一曲!", Toast.LENGTH_SHORT).show();
                return;
            }
            currnetPlayPosition = currnetPlayPosition + 1;
            LocalMusicBean nextBean = mDatas.get(currnetPlayPosition);
            playMusicInMusicBean(nextBean);
        } else if (viewId == R.id.local_music_bottom_iv_play) {
            if (currnetPlayPosition == -1) {
                // 并没有选中要播放的音乐
                Toast.makeText(this, "请选择想要播放的音乐", Toast.LENGTH_SHORT).show();
                return;
            }
            if (mediaPlayer.isPlaying()) {
                // 此时处于播放状态,需要暂停音乐
                pauseMusic();
            } else {
                // 此时没有播放音乐,点击开始播放音乐
                playMusic();
            }
        }
    }



四.效果展示

点击上一曲与下一曲,功能也能正常运作

五.总结

在此次的项目中,实现了基本的歌曲播放与切换功能,但实用性还是较差,并且在播放音乐时,能明显感觉到与专业音乐播放器音质也有所区别,另一方面是底部button会遮挡住左侧展示的歌曲名目信息,在将来的as学习中,我会把这个音乐播放器不断精进,使其功能更加完备。

源码仓库:start/简易音乐播放器

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值