通过调用安卓的MediaPlayer能够直接完毕Mp3等主流音频的播放,同一时候利用ContentResolver与Cursor能够直接读取安卓内在数据库的信息。直接获取当前sdcard中全部音频的列表,无须像《【Android】内存卡图片读取器。图库app》(点击打开链接)一样利用原始的Java代码去遍历整个sdcard卡,直接调用安卓固有的类既便捷又高速。最后。读取出来的Mp3能够通过适配器直接载入到ListView列表,做出例如以下所看到的的内存卡Mp3播放器app效果。本app在自己的真实的16G内存卡上真机測试通过。

首先,如果在内存卡上有例如以下的5个mp3文件,这里顺带提一句。利用DDMS复制文件到内存卡的时候注意,亲測发现,无法送PC上一个中文命名的文件到安卓虚拟机AVD。仅仅能送英文文件。不嫌麻烦,能够先改名再传输,到安卓虚拟机AVD再改名。或者直接用英文歌曲。

DDMS的使用能够參考《【Android】把外部文件拷贝的AVD安卓模拟器上的sdcard上。而且在AVD中浏览sdcard的文件》(点击打开链接)。

之后。例如以下图所看到的,实现一个mp3播放器的大致功能,能够调节音量,上一首、下一首、播放等等。在没有选定音乐这些button禁用。

制作步骤例如以下:

1、首先在res\values\strings.xml设置各个button与菜单的字体例如以下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3.  
  4. <string name="app_name">内存卡mp3播放器</string>
  5. <string name="action_settings">Settings</string>
  6. <string name="button1">上一首</string>
  7. <string name="button2">暂停</string>
  8. <string name="button3">停止</string>
  9. <string name="button4">下一首</string>
  10. <string name="menu_author">作者:yongh701</string>
  11. <string name="menu_exit">退出</string>
  12.  
  13. </resources>

2、其次,如《【Android】日期拾取器、时间拾取器与菜单》(点击打开链接)一样。对res\menu\main.xml进行改动,设定一个非常easy的菜单:

  1. <menu xmlns:android="http://schemas.android.com/apk/res/android" >
  2.  
  3. <item
  4. android:id="@+id/menu_exit"
  5. android:title="@string/menu_exit"/>
  6. <item android:title="@string/menu_author"/>
  7.  
  8. </menu>

3、然后,因为设置sdcard的操作与改变系统的媒体音量,须要到AndroidManifest.xml申请权限,此文件改动之后例如以下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.mp3player"
  4. android:versionCode="1"
  5. android:versionName="1.0" >
  6.  
  7. <uses-sdk
  8. android:minSdkVersion="8"
  9. android:targetSdkVersion="18" />
  10.  
  11. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 要求向SDCard读取数据权限 -->
  12. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 要求向SDCard写入数据权限 -->
  13. <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <!-- 要求改变音量的权限 -->
  14.  
  15. <application
  16. android:allowBackup="true"
  17. android:icon="@drawable/ic_launcher"
  18. android:label="@string/app_name"
  19. android:theme="@style/AppTheme" >
  20. <activity
  21. android:name="com.mp3player.MainActivity"
  22. android:label="@string/app_name" >
  23. <intent-filter>
  24. <action android:name="android.intent.action.MAIN" />
  25.  
  26. <category android:name="android.intent.category.LAUNCHER" />
  27. </intent-filter>
  28. </activity>
  29. </application>
  30.  
  31. </manifest>

4、之后,改动res\layout\activity_main.xml对MainActivity.java进行布局。

思想例如以下图:

在一个自上而下垂直的线性布局下,摆两个横向的水平线性布局与一个列表视图ListView,宽度皆匹配父布局。当中。第一个横向的水平线性布局通过《【Android】利用相对布局布置更新软件的style为主题对话框的Activity,利用layout_weight属性对表格布局的行划分》(点击打开链接)提及到的方式,等分放置四个button,其次,在第二个横向的水平线性布局,放置一个仅包裹内容的。用于文字显示音量的TextView与一个进度条SeekBar。这两个横向的水平线性布局的高度都是仅包裹内容就可以。最后的ListView的高度直接匹配父布局。因此,代码例如以下:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="match_parent"
  3. android:layout_height="match_parent"
  4. android:orientation="vertical" >
  5.  
  6. <LinearLayout
  7. android:layout_width="match_parent"
  8. android:layout_height="wrap_content"
  9. android:orientation="horizontal" >
  10.  
  11. <Button
  12. android:id="@+id/button1"
  13. android:layout_width="0dip"
  14. android:layout_height="match_parent"
  15. android:layout_weight="1"
  16. android:text="@string/button1" />
  17.  
  18. <Button
  19. android:id="@+id/button2"
  20. android:layout_width="0dip"
  21. android:layout_height="match_parent"
  22. android:layout_weight="1"
  23. android:text="@string/button2" />
  24.  
  25. <Button
  26. android:id="@+id/button3"
  27. android:layout_width="0dip"
  28. android:layout_height="match_parent"
  29. android:layout_weight="1"
  30. android:text="@string/button3" />
  31.  
  32. <Button
  33. android:id="@+id/button4"
  34. android:layout_width="0dip"
  35. android:layout_height="match_parent"
  36. android:layout_weight="1"
  37. android:text="@string/button4" />
  38.  
  39. </LinearLayout>
  40.  
  41. <LinearLayout
  42. android:layout_width="match_parent"
  43. android:layout_height="wrap_content"
  44. android:orientation="horizontal" >
  45.  
  46. <TextView
  47. android:id="@+id/textView1"
  48. android:layout_width="wrap_content"
  49. android:layout_height="wrap_content" />
  50.  
  51. <SeekBar
  52. android:id="@+id/seekBar1"
  53. android:layout_width="match_parent"
  54. android:layout_height="wrap_content" />
  55. </LinearLayout>
  56.  
  57. <ListView
  58. android:id="@+id/listView1"
  59. android:layout_width="match_parent"
  60. android:layout_height="match_parent" >
  61. </ListView>
  62.  
  63. </LinearLayout>

5、最后,是本app实现的核心,对MainActivity.java进行编写。大体上分为三部分:各个组件的代码实现、菜单的实现与返回按键的监听。之所以对返回物理button的监听。是由于须要要求。用户在按返回物理button是彻底退出程序。退出程序时候。还要释放被本app占用系统的MediaPlayer,因此还要重写onDestory方法。释放资源。

否则在程序退出之后,播放的音乐依旧会“绕梁三日”。

在组件代码实现的部分。还有例如以下细分。注冊各个组件之后。能够直接利用ContentResolver contentResolver = getContentResolver();获取安卓系统的数据接口,这个数据接口是安卓系统内部的数据库。里面存放着几张记录当前系统全部媒体,类似图片、音乐、视频等信息的表,通过Cursor这个数据库的迭代器。或者叫游标,反正是iterator对表进行遍历,能够直接取出媒体的信息。这里取走最关键的信息,无须用Java原始的遍历方法《【Java】读取其下全部目录与文件的路径》(点击打开链接),迭代求出各个音乐媒体的路径,产生巨大的时间复杂度。

  1. package com.mp3player;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.Collections;
  5.  
  6. import android.media.AudioManager;
  7. import android.media.MediaPlayer;
  8. import android.os.Bundle;
  9. import android.provider.MediaStore;
  10. import android.app.Activity;
  11. import android.content.ContentResolver;
  12. import android.content.Context;
  13. import android.database.Cursor;
  14. import android.view.KeyEvent;
  15. import android.view.Menu;
  16. import android.view.MenuItem;
  17. import android.view.View;
  18. import android.view.View.OnClickListener;
  19. import android.widget.AdapterView;
  20. import android.widget.AdapterView.OnItemClickListener;
  21. import android.widget.ArrayAdapter;
  22. import android.widget.Button;
  23. import android.widget.ListView;
  24. import android.widget.SeekBar;
  25. import android.widget.SeekBar.OnSeekBarChangeListener;
  26. import android.widget.TextView;
  27. import android.widget.Toast;
  28.  
  29. public class MainActivity extends Activity {
  30. private MediaPlayer mediaPlayer = new MediaPlayer();
  31. private ListView listView1;
  32. private ArrayList<String> audioList;// 存放音乐路径的动态数组
  33. private int currentAudioId;
  34. private Button button1;
  35. private Button button2;
  36. private Button button3;
  37. private Button button4;
  38. private TextView textView1;
  39. private SeekBar seekBar1;
  40.  
  41. @Override
  42. protected void onCreate(Bundle savedInstanceState) {
  43. super.onCreate(savedInstanceState);
  44. setContentView(R.layout.activity_main);
  45. // 注冊各个组件
  46. listView1 = (ListView) findViewById(R.id.listView1);
  47. button1 = (Button) findViewById(R.id.button1);
  48. button2 = (Button) findViewById(R.id.button2);
  49. button3 = (Button) findViewById(R.id.button3);
  50. button4 = (Button) findViewById(R.id.button4);
  51. textView1 = (TextView) findViewById(R.id.textView1);
  52. seekBar1 = (SeekBar) findViewById(R.id.seekBar1);
  53. // 初始状态“暂停/播放”按钮不可用,由于没有选定音乐
  54. button1.setEnabled(false);
  55. button2.setEnabled(false);
  56. button3.setEnabled(false);
  57. button4.setEnabled(false);
  58. // 载入音乐资源
  59. ContentResolver contentResolver = getContentResolver();
  60. Cursor cursor = contentResolver.query(
  61. MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
  62. MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
  63. audioList = new ArrayList<String>();
  64. for (cursor.moveToFirst(); !(cursor.isAfterLast()); cursor.moveToNext()) {
  65. String path = cursor.getString(cursor
  66. .getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
  67. audioList.add(path);
  68. }
  69. Collections.sort(audioList);
  70. ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,
  71. android.R.layout.simple_list_item_1, audioList);
  72. listView1.setAdapter(arrayAdapter);
  73. listView1.setOnItemClickListener(new OnItemClickListener() {
  74. @Override
  75. public void onItemClick(AdapterView<?
  76.  
  77. > arg0, View arg1,
  78. int position, long arg3) {
  79. currentAudioId = position;
  80. String path = audioList.get(currentAudioId);
  81. playMusic(path);
  82. button1.setEnabled(true);
  83. button3.setEnabled(true);
  84. button4.setEnabled(true);
  85. }
  86. });
  87. Toast.makeText(MainActivity.this,
  88. "音乐载入完毕,共" + audioList.size() + "首音乐", Toast.LENGTH_SHORT)
  89. .show();
  90. // 调节音量的功能
  91. final AudioManager audioManager = (AudioManager) MainActivity.this
  92. .getSystemService(Context.AUDIO_SERVICE);// 音乐管理器必须使用final类在OnCreate中定义
  93. MainActivity.this.setVolumeControlStream(AudioManager.STREAM_MUSIC);// 调节的是媒体音量
  94. seekBar1.setMax(audioManager
  95. .getStreamMaxVolume(AudioManager.STREAM_MUSIC));// 设置音量条的最大值为系统媒体音量的最大值
  96. int volume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);// 当前媒体音量
  97. seekBar1.setProgress(volume);
  98. textView1.setText("音量:" + volume);
  99. seekBar1.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
  100. @Override
  101. public void onStopTrackingTouch(SeekBar arg0) {
  102. }
  103.  
  104. @Override
  105. public void onStartTrackingTouch(SeekBar arg0) {
  106. }
  107.  
  108. @Override
  109. public void onProgressChanged(SeekBar arg0, int progress,
  110. boolean arg2) {
  111. textView1.setText("音量:" + progress);
  112. audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
  113. progress, AudioManager.FLAG_PLAY_SOUND);// 设置改变之后的音量
  114. }
  115. });
  116. // 各个按钮的点击监听
  117. // 上一首
  118. button1.setOnClickListener(new OnClickListener() {
  119. @Override
  120. public void onClick(View arg0) {
  121. currentAudioId--;
  122. if (currentAudioId < 0) {
  123. currentAudioId = 0;
  124. }
  125. String path = audioList.get(currentAudioId);
  126. playMusic(path);
  127. }
  128. });
  129. // 暂停/播放按钮
  130. button2.setOnClickListener(new OnClickListener() {
  131. @Override
  132. public void onClick(View arg0) {
  133. if (mediaPlayer.isPlaying()) {
  134. mediaPlayer.pause();
  135. button2.setText("继续");
  136. } else {
  137. mediaPlayer.start();
  138. button2.setText("暂停");
  139. }
  140. }
  141. });
  142. // 停止按钮
  143. button3.setOnClickListener(new OnClickListener() {
  144. @Override
  145. public void onClick(View arg0) {
  146. // TODO Auto-generated method stub
  147. if (mediaPlayer.isPlaying()) {
  148. mediaPlayer.stop();
  149. }
  150. button2.setEnabled(false);
  151. button3.setEnabled(false);
  152. }
  153. });
  154. // 下一首按钮
  155. button4.setOnClickListener(new OnClickListener() {
  156. @Override
  157. public void onClick(View arg0) {
  158. // TODO Auto-generated method stub
  159. currentAudioId++;
  160. if (currentAudioId > audioList.size() - 1) {
  161. currentAudioId = audioList.size() - 1;
  162. }
  163. String path = audioList.get(currentAudioId);
  164. playMusic(path);
  165. }
  166. });
  167. }
  168.  
  169. // 播放音乐
  170. public void playMusic(String path) {
  171. try {
  172. if (mediaPlayer.isPlaying()) {
  173. mediaPlayer.stop();
  174. }
  175. mediaPlayer.reset();
  176. mediaPlayer.setDataSource(path);
  177. mediaPlayer.prepare();
  178. mediaPlayer.start();
  179. } catch (Exception e) {
  180. e.printStackTrace();
  181. }
  182. button2.setEnabled(true);
  183. button2.setText("暂停");
  184. button3.setEnabled(true);
  185. Toast.makeText(MainActivity.this, "播放:" + path + "", Toast.LENGTH_SHORT)
  186. .show();
  187. }
  188.  
  189. // 退出程序时,释放当前音乐资源
  190. protected void onDestroy() {
  191. super.onDestroy();
  192. if (mediaPlayer.isPlaying()) {
  193. mediaPlayer.stop();
  194. }
  195. mediaPlayer.release();
  196. }
  197.  
  198. // 创建menu的方法,没有该方法,不会在右上角设置菜单。
  199. @Override
  200. public boolean onCreateOptionsMenu(Menu menu) {
  201. // 设置menu界面为res\menu\menu.xml
  202. getMenuInflater().inflate(R.menu.main, menu);
  203. return true;
  204. }
  205.  
  206. // 处理菜单事件
  207. public boolean onOptionsItemSelected(MenuItem item) {
  208. // 得到当前选中的MenuItem的ID,
  209. int item_id = item.getItemId();
  210. switch (item_id) {
  211. // 设置id为menu_exit的菜单子项所要运行的方法。
  212.  
  213. case R.id.menu_exit:
  214. System.exit(0);// 结束程序
  215. break;
  216. }
  217. return true;
  218. }
  219.  
  220. // 对物理按钮的监听
  221. @Override
  222. public boolean onKeyDown(int keyCode, KeyEvent event) {
  223. switch (keyCode) {
  224. case KeyEvent.KEYCODE_BACK:
  225. System.exit(0);
  226. break;
  227. }
  228. return super.onKeyDown(keyCode, event);
  229. }
  230. }

之后。对于读取出来的文件信息。直接用适配器载入到ListView列表。

随后对各个按钮的监听没什么好说的,记得播放的音乐时要先释放当前正在播放的音乐再上新曲,安卓系统不会自己覆盖播放。这里还须要处理一个载入音乐失败的异常。

在音量处理部分,须要自己创建一个音乐管理器AudioManager,此管理器必须在OnCreate方法中以final的形式定义,否则会出现例如以下图的错误:

通过音乐管理器可以获取与改变当前系统的媒体音量。可以把这个音量值载入到进度条,进度条的使用在《【Android】进度条与线程之间的消息处理》(点击打开链接)中已经讲过,这里不再赘述。

我还上了一份源代码给大家:http://download.csdn.net/detail/yongh701/8932343。欢迎交流,上次感谢网友提醒能够通过安卓系统内部的数据库拿到sdcard卡的媒体信息,我才省悟无须迭代这么麻烦。

【Android】利用安卓的数据接口、多媒体处理编写内存卡Mp3播放器app的更多相关文章

  1. 安卓MP3播放器开发实例(1)之音乐列表界面

    学习安卓开发有一年了,想想这一年的努力,确实也收获了不少.也找到了比較如意的工作. 今天准备分享一个以前在初学阶段练习的一个项目.通过这个项目我真正的找到了开发安卓软件的感觉,从此逐渐步入安卓开发的正 ...

  2. 安卓MP3播放器开发实例(3)之进度条和歌词更新的实现

    上一次谈了音乐播放的实现,这次说下最复杂的进度条和歌词更新.因为须要在播放的Activity和播放的Service间进行交互,所以就涉及了Activity对Service的绑定以及绑定后数据的传输,这 ...

  3. Android利用Filter过滤数据

    MainActivity如下: package cc.testfilterable; import java.util.ArrayList; import java.util.HashMap; imp ...

  4. [置顶] android利用jni调用第三方库——第二篇——编写库android程序直接调用第三方库libhello.so

    0:前言 1:本文主要作为丙方android公司的身份来写 2:作者有不对的地方,请指出,谢谢 [第一篇:android利用jni调用第三方库——编写库libhello.so] [第二篇:androi ...

  5. Android学习笔记_24_多媒体MediaPlayer对象之音乐播放器与SoundPool声音池

    一.MediaPlayer对象常用方法介绍: MediaPlayer mediaPlayer = new MediaPlayer(); if (mediaPlayer.isPlaying()) { m ...

  6. android开发之MediaPlayer+Service MP3播放器

    import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; import java.util.Lis ...

  7. android之MP3播放器(1)

    该播放器只是对本地的MP3文件进行简单的播放 布局文件 布局文件中设置了三个按钮分别来进行播放.暂停和继续播放 <?xml version="1.0" encoding=&q ...

  8. 从零开始学 Web 之 HTML5(四)拖拽接口,Web存储,自定义播放器

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  9. Android利用数据库传送数据

    ---恢复内容开始--- 一.建表 //通过SQLiteDatabase 创建数据库stu.db3 final SQLiteDatabase db = SQLiteDatabase.openOrCre ...

随机推荐

  1. Unity 实现Log实时输出到屏幕或控制台上<二>

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/49884507 作者:car ...

  2. COGS——T1588. [USACO FEB04]距离咨询

    http://cogs.pro/cogs/problem/problem.php?pid=1588 ★★   输入文件:dquery.in   输出文件:dquery.out   简单对比时间限制:1 ...

  3. Mongo集群之主从复制

    上线的系统.数据存储是重要部位.若一个公司的数据库部署还是待用单点部署,那若是宕机或是机器被损坏则是多糟糕的事情呀. 主从复制的部署方式为下图 主从复制是一个简单的数据库同步备份集群技术.这样的方式简 ...

  4. P3908 异或之和

    题目描述 求1 \bigoplus 2 \bigoplus\cdots\bigoplus N1⨁2⨁⋯⨁N 的值. A \bigoplus BA⨁B 即AA , BB 按位异或. 输入输出格式 输入格 ...

  5. python yield学习

    yield的功能类似于return,但是不同之处在于它返回的是生成器. 生成器生成器是通过一个或多个yield表达式构成的函数,每一个生成器都是一个迭代器(但是迭代器不一定是生成器). 如果一个函数包 ...

  6. mysql源码安装(包括5.5和5.7)

    1.mysql5.5源码安装 yum install -y cmake ncurses-devel ncurses cd /usr/src wget -c https://cdn.mysql.com/ ...

  7. Yeslab 华为安全HCIE-第七门-Agile Controlle

    课程目录:   华为安全HCIE-第七门-Agile Controller(12篇)\1_aglie_controller产品亮点讲解.avi 华为安全HCIE-第七门-Agile Controlle ...

  8. Python学习第一篇

    好久没有来博客园了,今天开始写自己学习Python和Hadoop的学习笔记吧.今天写第一篇,Python学习,其他的环境部署都不说了,可以参考其他的博客. 今天根据MachineLearning里面的 ...

  9. wangEditor - 轻量级web富文本编辑器(可带图片上传)

    业务需求: 通过后台编辑文章和图片,上传到前端界面,展示新闻消息模块.这个时候,需要一款简洁的编辑器,百度编辑器是最常用的一种,但是功能太过于复杂,而wangEditor - 轻量级web富文本编辑器 ...

  10. hdparm

    https://www.douban.com/note/244813504/ http://blog.sina.com.cn/s/blog_413d250e0101jtr7.html http://m ...