Android自定义音乐播放器
一:首先介绍用了哪些Android的知识点:
1 MediaPlayer工具来播放音乐
2 Handle。因为存在定时任务(歌词切换,动画,歌词进度条变换等)需要由Handle来处理Ui相关内容
3 动态权限申请(该应用程序读取本地歌曲,并且设置音质相关属性)且这两个权限在Android6.0后都需要动态申请
4 手势控制 (左划和右划需要满足一定条件后可以进行切歌)
5 Service服务 (启动Service 绑定Service 前台Service)
6 BroadcastReceiver 广播,Service与Activity,Activity与Activity存在动态交互,需要广播实现
7 基本的重写View能力和Intent交互数据的能力
8 Animation动画 图片旋转 歌词更新
二:实现过程(简要步骤,下面会详细讲解)
1 先编写MusicInfo工具类。因为我们是从手机内存中去读取音乐的相关信息,那么读出的数据该存储到MusicInfo工具类集合中。
2 先申请权限,然后再去手机内存将音乐及其相关的信息读出来 ,用一个ListView容器去装载所有的本地音乐
PS:到了这里基本的音乐信息列表已经有了 这也是我们的主界面(音乐列表界面) 即: 展示音乐/歌曲列表;
3 这时候先不方去实现播放这类的功能,我们先去处理歌词
这里说明一下。一个歌词文件(.Lrc)里面内容格式如下
(张卫健--真英雄)
可以发现他由时间戳和歌词内容两部分组成。有了这个信息后。编写LrcContent工具类,用于记录歌词内容和歌词时间。然后去手机里面寻找歌曲对应的歌词文件,将其编码,读出,装载为LrcContent集合。
4 编写Service类,Service主要用来处理:音乐播放,前台服务。在播放状态改变的时候与播放音乐的Activity进行通信。该Service由主界面启动,后面的Activity绑定即可
5 编写播放音乐的Activity类(MusicPlay)。当我们从主界面(音乐列表界面)点击了一首具体的音乐时,就会调转到该Activity,所有首先,主界面Activity需要传递一些信息给该Activity。
(1) MusicInfo工具类集合。即手机中所有的音乐信息
(2)当前点击的歌曲,传递位置(position)即可
好,现在我们播放音乐的Activity有了所有的音乐信息,还有当前需要播放的歌曲位置。因为需要前台服务,所以我们把音乐播放的控制权交给Service,我们去绑定服务,然后把所有的音乐信息,还有当前需要播放的歌曲位置都传递给Serivce,Service来控制播放音乐。
6 好了,现在我们的程序可以播放音乐了,我们再来一步步完善细节,歌词同步,该功能自定义View实现,最后显现在播放音乐的Activity中。注意Mediaplayer有一个重要属性:
mediaPlayer.getCurrentPosition()。该方法会返回当前播放时间,不过返回的时候时毫秒(重)。
自定义View(LrcView 显示歌词),该View中除了传统的自定义View需要的OnDraw之类的方法外,还需要获取第三步中的LrcContent集合,有了这个我们就有了所有的歌词内容和歌词相应的时间,那么同步如何实现呢?音乐最终该View要显示在播放音乐的Activity(MusicPlay)中,我们去MusicPlay的布局文件申明该View,然后在MusicPlay中编写一个定时器,可以设定每一秒启动一次,定时器发送消息,在Handle中接受消息,处理消息。Handle中我们需要:获取歌曲当前播放时间,根据当前播放时间去LrcContent集合中寻求匹配的歌词。用invalidate()方法,通知自定义View重绘,来同步更新歌词
7 我们的音乐播放器还差一个重要的东西,音乐控制器部分。这部分需要来控制播放上一首,下一首,播放/暂停,音乐进度拖动,音量设置。
该部分不难,所以再这里不详细讲。
三:效果图 因为完整录制的GIF太大,传不上来所以分批处理
四:代码精讲 代码量也不很大,但是全贴出来挨着讲又影响阅读。所以部分节选和重要知识点一并讲解。
PS:源码中含有大量System.out.println("XXXX");语句。个人比较偏爱的一种测试方式。。应该不干扰阅读,忘见谅
1 权限获取,我们要做的第一件事就是去内存读取音乐相关信息,那么我们就需要获得相关的权限,从Android6.0开始部分权限不仅需要在AndroidManifest.xml文件中声明,还需要在运行程序的时候动态获取.这里以读取存储权限为例:
首先在AndroidManifest.xml中定义
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
在Java业务代码中先判断是否已经有权限,有权限就不再申请,没有就申请权限
//首先检查自身是否已经拥有相关权限,拥有则不再重复申请
int check = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) ;
//没有相关权限
if (check != PackageManager.PERMISSION_GRANTED)
{
//申请权限 STORGE_REQUEST = 1
ActivityCompat.requestPermissions(this , new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE} ,STORGE_REQUEST);
}else {
//已有权限的情况下可以直接初始化程序
init();
}
当我们申请权限后,去判断用户是否给与了相关权限,如果赋予了就可以做我们的事情了
/*
申请权限处理结果
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode)
{
case STORGE_REQUEST :
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
//完成程序的初始化
init();
System.