音乐播放器 第3节 获取音乐信息

第3节 获取音乐信息

在“视频播放器”的开发过程当中,我们已经学会了如何获取视频文件的信息:

  1. 定义一个视频信息的数据结构VideoItem
  2. 自定义一个AnsycTask,在它的工作线程中查询视频;
  3. 在工作线程中,访问MediaProvider,获取视频数据;
  4. 将视频数据显示到自定义的列表项中;

这里列举音乐文件,也采用类似的方式:

  1. 定义一个音乐信息的数据结构MusicItem
  2. 自定义一个AnsycTask,在它的工作线程中查询音乐;
  3. 在工作线程中,访问MediaProvider,获取音乐数据;
  4. 将音乐数据显示到自定义的列表项中;

3.1 音乐数据的获取原理

与获取视频信息的方式几乎一样,获取音乐信息也是通过系统自带的MediaProviderMediaProvider里面存储了所有的多媒体数据信息,不仅有视频,还包括各种音频文件。

  1. Media Provider发出查询请求的地址-uri,它就像访问网站时,要输入的网址一样。系统提供了两个位置的uri,一个是指向内部存储的uri,一个是指向外部存储的uri。我们要查询的音乐文件都是存放在外部存储地址上的;

  2. 确定要请求的视频文件信息。在视频列表中,我们需要展示视频的标题、创建时间,还需要播放它时使用的文件所在地址。这些信息在Media Provider中都对应着查询它们使用的字段名称;

  3. 确定查询的条件。我们之前假设过:只关心那些包含了music关键字的目录。因此我们要确定的只是查询到的文件路径中,包含有music这个字段。

    这个条件参数的写法就和SQL数据库语言的语法一样。这里我们不打算讲SQL语法,只要知道在我们这个例子中这样使用就好了;

  4. 设定查询结果的排序方式,使用默认的排序方式就可以了,

  5. 获取ContentResolver对象,让它使用前面的参数向Media Provider发起查询请求;查询的结果存放在Cursor--指标当中;

  6. 遍历Cursor,得到它指向的每一条查询到的信息;当Cursor指向某条数据的时候,我们就获取它携带的每个字段的值;

    每首音乐都有一个全局唯一的URI地址,操作某首具体的音乐就可以通过这个地址来完成。而id就是用来获取该音乐的URI地址的,将id与音频的URI地址组合一下就能得到特定某首音乐的URI地址,它的形式就像content://media/external/audio/media/20310

    获取音乐的封面,

    1. 需要知道它所属的专辑idalbumId

    2. 根据这个id与专辑封面的uri(content://media/external/audio/albumart)组合,得到专辑所在的Uri,它的形式就像content://media/external/audio/albumart/4

    3. 通过下面的方式,创建出封面图片,

      这是一个很多模块都可能用到的功能,我们将它做成一个函数,放到Utils.java文件中,便于其它模块使用,

  7. 存放获取的视频文件信息,创建一个MusicItem类

    创建封面图片的方法上面已经介绍过了。一开始,我们可以暂时不用创建出封面图片,只保留albumId,在需要的时候再去创建出封面,一旦创建出封面图片,就把它保存在thumb这个成员变量当中。

    创建一个MusicItem

  8. Cursor使用完了之后要把它关闭掉,


整理一下前面的各个步骤,获取外部存储上music目录中所有音频文件的方式如下,

最后一点千万不要忘记,要在应用的AndroidManifest.xml文件中,添加读取外部存储器的权限,

3.2 在工作线程中获取音乐信息

主线程中不能做耗费时间到事情,如果要进行耗时的操作需要开启一个工作线程,把耗时操作交给工作线程处理。查询音乐的信息就是一个耗时的操作(准确的说是不知道什么时候能查询完,如果设备上的音乐文件很少,那么也许很快就完成了,但如果音乐文件很多,也会会花上很多很多时间)。

为此,我们还是采用“视频播放器”中的设计,创建一个叫做MusicUpdateTaskAsyncTask,在它的doInBackground()方法中去进行查询操作。

AsyncTask的原理和用法,我们已经在“视频播放器”的部分详细讲过了,这里就假设大家对它的使用已经比较熟悉了。

与“视频播放器”的设计不同,这里我们简化了设计,只用到了AsyncTaskonProgressUpdate()方法和doInBackground()方法。

另外,在列表加载的过程中,也没有让用户手动选择停止加载列表的功能。如果你觉得这个功能很重要,可以模仿“视频播放器”的设计,在这里添加上。我们在这里取消了这个设计,主要的目的只是为了让大家快速的梳理一下曾经具有的开发经验,节省时间,从而尽快的将我们带入带新的开发知识上去。

在使用MusicUpdateTask的时候,在主界面所在的MusicListActivity创建和销毁时,分别启动和取消MusicUpdateTask的运行,

3.3 音乐列表展示

我们给音乐列表设计了如下的界面,

我们已经知道了如何实现一个自定义的列表,

  1. 为每一条列表项定义它的外貌-布局文件;
  2. 自定义一个Adapter,将要展示的数据放入其中;
  3. 在主界面的布局文件中放入ListView控件,将Adapter设置到ListView中,让ListView展示所有数据;

3.3.1 音乐项的界面布局

每个数据项,要展示音乐的封面、名称、播放时长,

为此,我们给它定义个布局music_item.xml,将界面区域这样分割:

  1. ImageView用来放置歌曲封面,给它指定一个图片的大小,150dp x 100dp;背景颜色采用主题属性colorPrimary的颜色;

  2. 封面的id设置成music_thumb,音乐名称的id设置成music_title,播放时长的id设置成music_duration

整个布局方式如下,

3.3.2 自定义Adapter

这里自定义MusicItemAdapter的方法,与自定义VideoItemAdapter的方法几乎一模一样,只是,

  1. Adapter保存的数据类型不同,从VideoItem变成了MusicItem

  2. 时间格式我们将显示成32:21这种形式,所以可以采用这样的实现,

    这是一个很多模块都可能用到的功能,我们将它做成一个函数,放到Utils.java文件中,便于其它模块使用,

MusicItemAdapter的实现如下,

3.3.3 通过ListView使用Adapter

有了Adapter和数据,就要把它们结合起来,放到ListView中,以列表的形式展示出来。

  1. MusicListActivity的布局activity_music_list.xml当中,加入列表,

  2. onCreate()中,创建Adapter,并设置给ListView

  3. MusicUpdateTask获取的音乐数据放入到ListView当中,需要完善MusicUpdateTask()方法,

因为列表中显示封面的时候,创建了不少图片,在Activity退出的时候,我们要手动的回收这些图片占用的空间,


好了,当我们运行应用的时候,就会看到设备上music目录下的音乐都被显示出来了。

3.4 测试音乐播放

音乐列表准备好了,我们来试试播放音乐吧。
前面我们介绍了如何使用MediaPlayer来播放音乐,这里我们让用户点击音乐列表上的特定音乐后,就开始播放它,

  1. 为音乐列表的音乐项设置点击的监听,

  2. 在点击响应处,添加播放音乐的代码,

    每次点击前都调用一次mMusicPlayer.reset(),可以清除以前播放器的状态。

这样一来,用户点击音乐的时候,就可以播放制定的音乐了。

**注意,这里只是为了让我们直观的感受到音乐列表的完成,并能够播放音乐,但是程序的框架并没有按照我们之前设计那样,所以只能算是效果的验证。

在后面的章节中,我们将修改这里的设计,按照正确的设计框架来实现音乐播放。**

所以最后,让我们清除这段测试播放音乐用的代码吧。

/**************************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。
/
**************************************************************************/