Android手机音乐播放器
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
武汉职业技术学院毕业设计论文
课程名称:面向对象课程设计
题目:Android手机音乐播放器
专业:软件技术
班级:软件09301班
姓名:
学号:
指导老师:
2011 年12月15日至2011年12月25日
程序设计任务书
设计题目:手机音乐播放器
设计目的
本课程的设计的目的是通过实践使同学们经历android开发全过程和受到一次综合训练,以便能较全面地理解、掌握和综合运用所学的知识。
结合具体的开发案例,理解并初步掌握系统分析、系统设计、系统实施的主要环节和步骤以及软件文档的制作能力。
要求完成的主要任务:
(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)
主要任务:
1.完成主界面设计
2.选择要播放的文件,构成播放列表
3.实现播放、暂停、结束功能
4.实现音量调节和循环播放选择功能
5.实现后台运行
设计报告撰写格式要求:
大标题:黑体三号字加粗
小标题:宋体四号字加粗
正文:宋体五号字
时间安排:16周-19周
消化资料、系统调查 1天系统分析 1天
总体设计 2天实施计划(编写代码) 3天
撰写报告1天演示、验收1天
具体要求
1、明确课程设计的目的和重要性,认真领会课程设计的题目,学会设计的基本方法与步骤,学会如何运用前修知识与收集、归纳相关资料解决具体问题的方法。
严格要求自己,要独立思考,按时、独立完成课程设计任务。
2、设计报告:要求层次清楚、整洁规范、不得相互抄袭,凡正文内容有整段完全相同者一律以抄袭论处。
设计报告正文字数不少于0.2万字(不包括附录)
指导教师签字:年月日
系主任签字:年月日
一、播放器的主要功能
1、自动查找sd卡中的音乐播放文件,生成播放列表。
2、具有播放,暂停,下一曲,上一曲,循环播放的功能。
3、打接电话时音乐停止,挂掉电话后重新回到播放界面继续播放音乐。
4、可以进行后台播放功能。
5、若新增MP3格式的音乐文件可以自动将该音乐文件添加到播放列表。
二、使用到的相关知识
Android各种页面布局,Android中的MediaPlayer媒体创建,Android中service后台控制播放方法,Intent意图进行Activity之间进行多页面跳转,Button 按钮事件监听控制,
三、实现该音乐播放器的整体思路
要实现这个音乐播放器。
首先应该考虑到的就是他的功能,要有后台播放功能以及显示正在播放的文件和把手机中的音乐文件以列表的形式显示在手机上,这就要使用到listview类。
另外在本地歌曲列表和正在播放的歌曲之间要进行动态菜单的跳转故而想
到用tabhost这个容器进行布局。
后台播放创建一个类继承service方法,在该类中使其具有播放暂停下一首上一首的功能的方法,从而是它在各个Activity之间进行跳转的时候为其他的类提供相应的方法。
创建一个新建文件类和过滤文件信息的类,用以存贮特定的文件信息和当用户改变文件夹终不改的内容的时候同步更新播放列表。
于接打电话这个问题,创建一个类进行监听,当电话进来或出去的时候调用service方法停止音乐播放并记下播放点。
四、在实现过程遇到的相关问题以及解决的办法
对于刚接触Android开发的我们,在很多的知识点上还是不是很理解,鉴于此在制作的过程难免会遇到各种问题,解决的办法就是通过百度,goolge各种搜索引擎。
1、首先在开始动手构思音乐播放器界面的时候就遇到了难题,要实现动态菜单(本地音乐、正在播放的歌曲);
2、如何实现后台播放;
3、如何进行多页面之间的跳转;
4、如何进行电话监听;
5、如何将sd卡中的MP3音乐文件过滤读取到播放列表中;
6、如何自动添加更新播放列表;
7、对于listview中点击Item时触发相应的播放事件;
五、得到MP3界面图展示
:
六、具体实现步骤
1、创建main.xml 布局文件。
通过tabhost 进行布局显示本地播放和正在播放。
实现的主要代码及步骤效果图:
(1)main.xml
<TabHost
xmlns:android ="/apk/res/android" android:layout_width ="match_parent"
android:layout_height ="match_parent"
android:id ="@android:id/tabhost">
<LinearLayout android:orientation ="vertical"
android:layout_width ="fill_parent"
android:layout_height ="fill_parent"
android:padding ="5dp">
<TabWidget android:id ="@android:id/tabs"
android:layout_width ="fill_parent"
android:layout_height ="wrap_content"
正在播放时候 本地歌曲列表
android:padding="5dp"/>
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp"/>
</LinearLayout>
</TabHost>
(2)创建TabViewActivity类继承TabActivity类向tabhost容器中加入动态menu以及创建一个music类进行sd卡的音乐文件的存取和读取,创建utilFile 进行文件的创建和判断。
在SD卡创建存放MP3的目录代码片段:
public void createDirInSDCard() throws IOException {
if(new File(FileUtils.MUSIC).exists() == false)
{
File file = new File(MUSIC);
file.mkdir();
}
}
在SD卡上创建文件代码片段:
public File creatFile(String fileName) throws IOException { File file = new File(MUSIC+fileName);
file.createNewFile();
return file;
}
/*
* 判断文件是否存在
*/
public boolean isFileExist(String fileName) {
File file = new File(MUSIC + fileName);
return file.exists();
}
向tabhost容器中加入动态菜单项的代码片段:
public void initializePlayer() {
// 因为继承了TabActivity,所以可以用getTabHost()获取TabHost,
tabHost = this.getTabHost();
// 设置Intent指向的类
intent = new Intent(this, LocalListActivity.class);
// 创建一个tabSpec,并设置它的标签和要跳转到的Intent
tabSpec = tabHost.newTabSpec("local").setIndicator("本地歌曲")
.setContent(intent);
// 将tabSpec添加到tabHost(这样就把一个分页的标签添加进去了)
tabHost.addTab(tabSpec);
//添加第二个标签
intent = new Intent(this, PlayingMusicActivity.class);
tabSpec = tabHost.newTabSpec("playingMusic").setIndicator("歌曲播放")
.setContent(intent);
tabHost.addTab(tabSpec);
(3)创建Mp3Info类,定义初始话音乐信息
private static final long serialVersionUID = 1L;
private String id ;
private String mp3Name;
private String author;
private String lrcName ;
private String lrcSize ;
public Mp3Info()
{
}
public Mp3Info(String id, String mp3Name, String author, String lrcName,
String lrcSize) {
super();
this.id = id;
this.mp3Name = mp3Name;
this.author = author;
this.lrcName = lrcName;
this.lrcSize = lrcSize;
}
public String toString() {
return"Mp3Info [author="+ author+ ", id="+ id+ ", lrcName="
+ lrcName + ", lrcSize=" + lrcSize + ", mp3Name=" + mp3Name
+ "]";
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMp3Name() {
return mp3Name;
}
public void setMp3Name(String mp3Name) {
this.mp3Name = mp3Name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getLrcName() {
return lrcName;
}
public void setLrcName(String lrcName) {
this.lrcName = lrcName;
}
public String getLrcSize() {
return lrcSize;
}
public void setLrcSize(String lrcSize) {
this.lrcSize = lrcSize;
}
}
2、创建playmusic.xml布局文件用以显示播放下一首上一首控制按钮和显示正在播放的音乐文件的名字
具体代码片段:
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout
xmlns:android="/apk/res/android"
android:baselineAligned="false"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="60dip">
<TextView
android:text="正在播放歌曲"
android:id="@+id/textView1"
android:layout_width="fill_parent"
android:textSize="10pt"
android:layout_height="wrap_content">
</TextView>
<TextView
android:layout_height="wrap_content"
android:textSize="10pt"
android:layout_width="wrap_content"
android:id="@+id/textView2"
android:text="TextView">
</TextView>
</LinearLayout>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="@+id/linearLayout2">
<Button
android:layout_height="wrap_content"
android:text="上一首"
android:layout_width="wrap_content"
android:id="@+id/last"
android:fadeScrollbars="true"
android:longClickable="true"
android:textSize="10pt">
</Button>
<Button
android:layout_height="wrap_content"
android:id="@+id/pause"
android:layout_width="wrap_content"
android:text="暂停"
android:longClickable="true"
android:textSize="10pt"></Button>
<Button
android:id="@+id/start"
android:visibility="gone"
android:layout_width="wrap_content"
android:text="播放"
android:textSize="10pt"
android:layout_height="wrap_content">
</Button>
<Button
android:text="下一首"
android:id="@+id/next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:longClickable="true"
android:textSize="10pt">
</Button>
</LinearLayout>
</LinearLayout>
3、创建一个playmusicService类行进后台控制音乐播放功能为Playmusic类用以控制音乐播放功能的方法。
Service代码片段:
public class PlayMusicService extends Service {
private static MediaPlayer mediaPlayer;
private static final String MUSIC_PATH = "/sdcard/Music/";
// 歌曲是否正在播放
public static boolean isPlaying = false;
// 当前播放的歌曲
public static int CURRENT_SONG = 0;
// 声明一个Bundle对象,用来放置接收到的Bundle对象
Bundle bundle = null;
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
// 生成MediaPlayer对象
mediaPlayer = new MediaPlayer();
}
@Override
public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub
super.onStart(intent, startId);
// 从接收到的Bundle对象中获取当前播放歌曲的位置
bundle = intent.getExtras();
CURRENT_SONG = bundle.getInt("position");
// 条用playMusic()方法播放歌曲
playMusic(CURRENT_SONG);
}
// 播放歌曲方法
public void playMusic(int position) {
try {
// 标志为正在播放
isPlaying = true;
// 获取将要播放的歌曲的位置
CURRENT_SONG = position;
System.out.println("当前正在播放的歌曲:"
+
LocalListActivity.list.get(CURRENT_SONG).get("mp3Name"));
mediaPlayer.reset();
mediaPlayer.setDataSource(MUSIC_PATH
+
LocalListActivity.list.get(CURRENT_SONG).get("mp3Name"));
mediaPlayer.prepare();
mediaPlayer.start();
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
/*
* 播放当前歌曲的下一首判断播放的是否最后一首歌,如果是,播放完返回播放第一首
*/
if(++CURRENT_SONG>= LocalListActivity.list.size()) {
CURRENT_SONG = 0;
}
playMusic(CURRENT_SONG);
// 动态更新正在播放歌曲的名字
new
PlayingMusicActivity().updatePlaySongName(CURRENT_SONG);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
// 播放上一首歌曲
public void lastMusic(int position) {
// 先把MediaPlayer对象切换到stoped状态
if (mediaPlayer != null){
if(isPlaying){
mediaPlayer.stop();
CURRENT_SONG = position;
if (CURRENT_SONG < 0) {
// 如果当前播放的是第一首歌,则切换到最后一首
CURRENT_SONG = LocalListActivity.list.size() - 1;
}
playMusic(CURRENT_SONG);
}
}
}
// 播放下一首歌曲
public void nextMusic(int position) {
// 先把MediaPlayer对象切换到stoped状态
if (mediaPlayer != null){
if(isPlaying)
{
mediaPlayer.stop();
CURRENT_SONG = position;
// 如果播放的是最后一首歌曲,则切换到第一首
if(CURRENT_SONG== (LocalListActivity.list.size())) { CURRENT_SONG = 0;
}
playMusic(CURRENT_SONG);
}
}
}
// 暂停/恢复播放
public void pauseMusic() {
if (mediaPlayer != null) {
if (isPlaying == true) {
mediaPlayer.pause();
isPlaying = false;
}
}
}
/*
* 恢复播放歌曲
*/
public void startMusic() {
if (mediaPlayer != null) {
if(isPlaying == false){
mediaPlayer.start();
isPlaying = true ;
}
}
创建playmusic类中在textview中进行显示显示正在播放的音乐文件名代码片段:
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
// TextView对象,设置正在播放的歌曲的名字
if (PlayMusicService.isPlaying == false) {
currentSong = playMusicService.CURRENT_SONG;
}
updatePlaySongName(PlayMusicService.CURRENT_SONG);
}
// 更新正在TextView对象
public void updatePlaySongName(int position) {
textView.setText(LocalListActivity.list.get(position).get("mp3 Name"));
}
4、创建LocallistActivity类用listview显示本地音乐文件以及local_listview.xml。
local_listview.xml代码片段:
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout
xmlns:android="/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="10"
android:drawSelectorOnTop="false"
android:id="@+id/local_listview"
/>
</LinearLayout>
LocallistActivity类实现OnItemClickListener接口
定义一些MP3的信息变量
private static final int TAG_SIZE = 128;
private static final int TITLE_SIZE = 30;
private static final int ARTIST_SIZE = 30;
private static final int ALBUM_SIZE = 30;
private static final int YEAR_SIZE = 4;
private static final String TAG_START = "TAG";
private ListView listView = null;
定义被点击的歌曲的位置:
public static int currentSong = 0;
定义一个list数组用以存储歌曲列表信息:
public static List<HashMap<String, String>> list = null;
重写onResume获取点击音乐的焦点事件:
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
try {
showLocalListView(FileUtils.MUSIC);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
创建文件过滤器,过滤非以"mp3"结尾的文件
private FilenameFilter fileFilter = new FilenameFilter() {
public boolean accept(File path,String name)
{
return (name.endsWith(".mp3"));
}
};
显示本地歌曲列表
public void showLocalListView(String path) throws Exception { listView= (ListView) this.findViewById(R.id.local_listview);
list = new ArrayList<HashMap<String, String>>();
HashMap<String, String> map = null;
File musicDir = new File(path);
File[] files = musicDir.listFiles(fileFilter);
for (int i = 0; i < files.length; i++) {
String filePath = files[i].getParent() + File.separator
+ files[i].getName();
File mp3 = new File(filePath);
byte[] buf = new byte[TAG_SIZE];
RandomAccessFile raf = new RandomAccessFile(mp3, "r");
raf.seek(raf.length() - TAG_SIZE);
raf.read(buf, 0, TAG_SIZE);
String tag = new String(buf, 0, TAG_SIZE, "gbk");
map = new HashMap<String, String>();
map.put("mp3Name", mp3.getName());
//获取MP3信息
map.put("mp3Author", tag.substring(33, 63).trim());
list.add(map);
}
创建一个simpleAdapter适配器和点击Item触发service中的播放音乐事件:SimpleAdapter simpleAdapter = new SimpleAdapter(this, list,
yout.local_item,
new String[] { "mp3Name" ,"mp3Author"}, new int[] {
R.id.mp3Name ,R.id.mp3Author});
listView.setAdapter(simpleAdapter);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setOnItemClickListener(this);
}
//点击ListView的Item时触发的时间
public void onItemClick(AdapterView av, View v, int position, long id) {
// TODO Auto-generated method stub
Intent serviceIntent = new Intent(this, PlayMusicService.class);
Bundle b = new Bundle();
//记录当前播放歌曲的位置
currentSong = position ;
//将被点击的歌曲的当前位置传递到service中
b.putInt("position", currentSong);
serviceIntent.putExtras(b);
startService(serviceIntent);
//跳转到第二标签卡
TabViewActivity.tabHost.setCurrentTab(1);
//更新正在播放歌曲名字
new PlayingMusicActivity().updatePlaySongName(currentSong);
}
}
5、创建一个与打接电话时音乐后台停止并且记住播放点,当打接电话完毕音乐继续播放的类继承BroadcastReceiver类。
该类的相关代码片段:
public void onReceive(Context contex t, Intent intent) {
/*
* 当来电或去电时,则暂停播放音乐
*/
if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
//去电时暂停
new PlayMusicService().pauseMusic();
}
else {TelephonyManager tm = (TelephonyManager) context
.getSystemService(Service.TELEPHONY_SERVICE);
//来电时暂停
switch (tm.getCallState()) {
case TelephonyManager.CALL_STATE_RINGING:
new PlayMusicService().pauseMusic();
break ;
}
}
6、对于Androidmainfest.xml注册文件的配置。
1)注册来电、去电的监听器
<receiver android:name=".receiver.PhoneReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"/>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/> </intent-filter>
</receiver>
2)添加来电读取权限
<uses-permission
android:name="android.permission.READ_PHONE_STATE"/>
3)添加监听去电的读取权限
<uses-permission
android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
总结:
首先应该说一句的是:要感谢这次课程设计,因为通过这次课程设计让我对Android的开发又有了更进一步的认识,例如以前不懂的tabhost布局这个容器通过这次例子我明白了它在制作动态菜单这方面具有重要意义,还有以前不明白怎么使音乐播放器具有后台播放的功能,在老师的提示要使用到Android提供的一个service方法后,我通过在网上下载的Android相关学习视频和一些网上用到的相关的例子终于明白了其实现的方法从创建一个service到摧毁destroy终止service。
在一开始的时候我并不知道怎么去实现音乐后台的播放功能,但是接触了service后我知道,将playmusic中用到的启动暂停等按钮控制音乐播放功能的按钮的事件放在service中然后通过外在类调用其start、stop等一些方法进行音乐的停止播放功能。
通过后台的实现同时我明白了,当在程序中我们要用到一些经常用到的方法
的时候我们可以单独的创建一个类专门的用来创建这些常用的方法,通过调用这个类去实现索要实现的功能,这样的同时我也更加的明白了什么叫面向对象,面向对象的真正的强大所在。
还有刚开始的时候由于因为一些事情的原因的少去上了几次课,从而对于跳转页面这个功能在Android中的实现不太明白,但是通过这次项目的编写,我知道怎么通过意图intent内部的类进行多页面之Activity间的跳转和数据的传递。
这次项目我也明白了androidmainfest.xml这个文件作用,当要在多哥页面之间进行跳转的时候我们在创建好相应的Activity后我们同时最好要androidmainfest.xml中进行注册。
还有一点更是这次项目中学到的东西,那就是打接电话的监听事件,由于这个音乐播放器要具有当电话来的时候音乐停止当电话结束后要有重新自动播放的功能,所以这就要调用android中给我们提供的对于打接电话这个事件专用的方法进行控制,然后当电话来的时候调用在service 中构造的相应的方法去实现所要得到的功能。
也同样在该次课程设计中体会到学习主动性的重要,要想学好一样东西,必须拿出很大的意义决心和毅力,在遇到问题的时候,要独立自主的去思考,并且合理的通过谷歌或者百度这两大神奇的东西去搜索答案,在项目刚开始的时候,我的思路全无,但是通过在网上搜索查看别人所写过的相关的项目的源代码,和一些功能实现的关键技术,从而才使得自己对MP3音乐播放器这个软件有了一定认识和设计思路。