您的当前位置:首页正文

安卓音乐播放器开发含源代码

2021-05-16 来源:易榕旅网


基于an droid平台的音乐播放器开发

实验报告

学生姓名: _______ 温从林 _________________ 学 号: ___________________________________ 班 级:

计自1201 _____________

第一章引言

1.1项目背景

当今社会的生活节奏越来越快,人们对手机的要求也越来越高,由于手机市场发 展迅速,使得手机操作系统也出现了不同各类,现在的市场上主要有三个手机操作系 统,Win dowsmobile,symbia n,以及谷歌的 An droid操作系统,其中占有开放源代码 优势的An droid系统有最大的发展前景。那么能否在手机上拥有自己编写的个性音乐 播放器呢?能的,谷歌 An droid系统就能做到。本文的音乐播放器就是基于谷歌 An droid手机平台的播放器。

An droid :是谷歌于2007年公布的开放式源代码手机系统,它的开放性就优于其 它封闭式的手机系统,因此,任何人都可能根据自己的喜好将手机系统中的所有功能 重新编写。这使得越来越多的人关注这个操作系统。本次作品音乐播放器就是基于 An droid平台的。

1.2编写目的

现今社会生活紧张,而欣赏音乐是其中最好的舒缓压力的方式之一,本项目的目 的是开发一个可以播放主流音乐文件格式的播放器,本设计实现的主要功能是播放 Mp3 Wav多种格式的音乐文件,并且能够控制播放,暂停,停止,播放列等基本播放 控制功能,界面简明,操作简单。

本项目是一款基于An droid手机平台的音乐播放器,使 An droid手机拥有个性的

多媒体播放器,使手机显得更生动灵活化,与人们更为接近,让手机主人随时随地处 于音乐视频的旋律之中。使人们的生活更加多样化。也使设计者更加熟练 技术和其它在市场上的特点。

An droid的

1.3开发环境

Eclipse、An droid SDK 320

第二章 系统需求分析

2.1功能需求(用例图分析)

根据项目的目标,我们可获得项目系统的基本需求,以下从不同角度来描述系统 的需求,并且使用用例图来描述,系统的功能需求,我们分成四部分来概括,即播放 器的基本控制需要,播放列表管理需求,播放器友好性需求和播放器扩展卡需求。以 下分别描述:

2.1.1播放器的用例图

假设安装了音乐播放器的用户是系统的主要设计对象,其拥有以下操作, 启动软件、播放音乐、暂停播放、停止播放、退出软件,其用例图如下

图2.1 播放器基本用例图

2.1.2用例分析

前置条件:无 基本事件流:1.用户启动软件 2. 用例名称:播放 参与者:用户 播放器将播放列表中的当前的歌曲 目标:使得用户可以播放在播放列表中选中的歌曲 前置条件:播放器正在运行 基本事件流:1.用户单击“播放”按钮 2. 用例名称:暂停 参与者:用户 播放器将播放列表中的当前的歌曲 目标:使得用户可以暂停正在播放的歌曲 前置条件:歌曲正在播放且未停止和暂停 基本事件流:1.用户单击“暂停”按钮 2. 用例名称:停止 参与者:用户 播放器将暂停当前的歌曲 目标:使得用户可以停止正在播放的歌曲 前置条件:歌曲正在播放或暂停 基本事件流:1.用户单击“停止”按钮 2. 用例名称:退出

播放器将停止当前播放的歌曲

参与者:用户

目标:使得用户退出或者后台播放音乐 前置条件:程序在运行 基本事件流:1.用户按返回键

2. 播放器退出或者进入后台播放

第三章概要设计

3.1软件播放流程图

Stepl.启动软件后,软件自动检索手机和 sd卡的音频文件,并组织显示成列表 Step2.点击列表的歌曲名字。 Step3.播放音乐。

Step4.点击暂停,音乐暂停 Step5.点击播放转到step3 Step6.点击停止停止播放音乐 Step7 .点击退出。

启动软件 自动检索手机中

暂停/退出软件

图3.1音乐播放器流

第四章 界面展示

4.1 软件部署

系统编译生成 apk 文件,将 apk 文件拷到手机或者 sd 卡中,直接打开即可 安装。

4.2 启动软件

打开软件后的界面

4.3 歌曲列表界面

歌曲列表界面

4.4 播放界面 4.5 收藏界面

4.6 在线搜索音乐界面

第五章 结 论

(1) 通过本次幵发解决了诸如 SD卡音乐文件搜索并显示、联网搜索歌曲等 难题,对安卓的开发有了更深入的认识。

(2) 通过对 Android 手机平台的音乐播放器软件的开发,使我对 Android 音乐播 放器系统的整体设计有一个深入的了解,对整个流程也会有一个清晰的认识。开发 Android 音乐播放器, 要抓住开发的核心部分, 音乐播放器大体由播放主界面、 播放列 表、菜单、播放设置、文件浏览、歌曲搜索六大核心组成。

(3) 本次程序设计,对播放器的系统结构框架做了精心的构思与设计,采用主要 开发工具是 Eclips4.0+Java 语言的支持, Android Development Tool 的插件,和 Android SDK2.1 版本的全面结合,才使整个音乐播放器系统得以实现

第五章 部分源代码

以下给出功能实现代码,布局,风格等代码量过大,放在压缩文件中

MainActivity.java:

package import import

import import import import import import import import

public class MainActivity extends ActionBarActivity { @Override

protected void onCreate(Bundle savedInstanceState) {

super .onCreate(savedInstanceState);

requestWindowFeature(Window. FEATURE_NO_TITLE); setContentView(R.layout. fragment_main ); Thread thread = new Thread() {

public void run() {

try {

sleep (2500);

} catch (InterruptedException e) {

e.printStackTrace();

}

finish();

Intent intent = new Intent(MainActivity. this , MusicActivity. class ); startActivity(intent);

}

};

thread.start();

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu. return true ;

}

main , menu);

@Override

public boolean onOptionsItemSelected(MenuItem item) { //

Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long

// as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id. action_settings ) {

return true ;

}

return super .onOptionsItemSelected(item);

}

* A placeholder fragment containing a simple view. */ public static class PlaceholderFragment extends Fragment {

public PlaceholderFragment() {

}

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container,

Bundle savedInstanceState) {

View rootView = inflater.inflate(R.layout. fragment_main false ); , container,

return rootView;

}

} }

package ; import import import import import import import import import import import import

BandanActivity.java

import

public class BangdanActivity

private private private private private private private private private private

ListView listview ; String musicpath ; int _ids []; String _titles []; String String[] String[]

_artists []; _path ; _times ;

extends Activity {

// 存放音乐文件的 id 数组 // 存放音乐文件的标题数组 存放音乐艺术家的标题数组 //

// 存放音乐路径的标题数组 // 存放总时间的标题数组 // 存放专辑的标题数组 // 存放文件大小的标题数组

; // 存放名称的标题数组

String[] _album ; int _sizes []; String[]

displayname

@Override protected

void onCreate(Bundle savedInstanceState) {

super .onCreate(savedInstanceState); setContentView(R.layout. bangdanmusic_list );

listview = (ListView) findViewById(R.id. bangdan_music_list );

listview .setOnItemClickListener( new MusicListOnClickListener()); ShowMp3List();

}

*显示MP3言息,其中」ds保存了所有音乐文件的_ID ,用来确定到底要播放哪一首歌曲,

_titles 存放音乐名,用来显示在播放界面,

*而_path存放音乐文件的路径(删除文件时会用到) private void ShowMp3List() {

// 用游标查找媒体详细信息 Cursor cursor =

this .getContentResolver().query(

EXTERNAL_CONTENT UR,I new String[] {

TITLE , DURATION, ARTIST,

// 标题,游标从 0读取 // 持续时间 ,1 // 艺术家 ,2 // id,3

*/

, DISPLAY_NAME, // 显示名称 ,4

// 数据, 5 DATA,

ALBUM_ID, // 专辑名称 ID,6 ALBUM, SIZE }, null

/** 将游标移到第一位 **/

cursor.moveToFirst();

/** 分别将各个标题数组实例化 **/ _ids = new int [cursor.getCount()]; _titles = new String[cursor.getCount()]; _artists = new String[cursor.getCount()]; _path = _album =

// 专辑 ,7

, null ART IST ); // 大小 ,8

new Strin g[cursor.getCo un t()]; new Strin g[cursor.getCo un t()];

_times = new Strin g[cursor.getCo un t()];

_displa yn ame = new Strin g[cursor.getCo un t()]; _sizes = new int [cursor.getCount()];

到的内容格式为/mnt/sdcard/[

的是/sdcard/[

子文件夹名]音乐文件名 */

for (int i = 0; i < cursor.getCount(); i++) {

_ids [i] = cursor.getInt(3); _titles [i] = cursor.getStri ng(0); _artists [i] = cursor.getStri ng(2);

_path [i] = cursor.getString(5).substring(4); /*****

以下是为提供音乐详细信息而生成的

******/

子文件夹名/]音乐文件名,而我们想要得到

_album [i] = cursor.getString(7); _times [i] = toTime(cursor.getInt(1)); _sizes [i] = cursor.getInt(8);

_displa yn ame [i] = cursor.getStri ng(4);

cursor.moveToNext();

}

listview .setAdapter( new MusicListAdapter( this , cursor)); }

/**时间的转换*/

public String toTime( int time) {

time /= 1000; int minute = time / 60; int second = time % 60; minute %= 60;

/**返回结果用string 的format方法把时间转换成字符类型 return }

/**音乐列表添加监听器,点击之后播放音乐 public class MusicList On ClickListe ner

@Override

public void on ltemClick(AdapterViewargO,

long id) {

musicpath =\"/mnt\" +_path [position]; playMusic( musicpath ); /*putExtraMusic(positio n); Intent

PlayMusicActivity. class );

startActivity(i ntent); fin ish();

intent

= new

*/

Inten t(Ba ngda nActivity.

this

View view, int

positi on,

*/

impleme nts On ItemClickListe ner {

Stri ng.

format (\"%02d:%02d\" , min ute, seco nd);

**/

}

public void playMusic(String musicpath) {

try {

MediaPlayer mp = new MediaPlayer();

mp.reset();

mp.setDataSource(musicpath); mp.prepare(); mp.start(); } catch (Exception e){

Toast. makeText (getApplicationContext(),

无法播放此文件

Toast. LENGTH_SHOR)T.show();

}

}

public void putExtraMusic( int position) { Intent intent

Intent(BangdanActivity. this ,PlayMusicActivity. class );

/*intent.putExtra(\"_ids\intent.putExtra(\"_path\intent.putExtra(\"_titles\intent.putExtra(\"_artists\intent.putExtra(\"position\startActivity(intent); finish();*/ intent =

new Intent();

Bundle bundle = new Bundle(); bundle.putInt(

\"position\" , 25);

intent.putExtras(bundle);

intent.setClass(BangdanActivity. this , PlayMusicActivity. class );

startActivity(intent); finish();

}

@Override

protected void onStop() {

super .onStop();

}

private long exitTime = 0;

public boolean onKeyDown( int keyCode, KeyEvent event) {

if (keyCode == KeyEvent. KEYCODE_BACK && event.getAction() KeyEvent.

ACTION_DOWN){

if ((System. currentTimeMillis ()- exitTime ) > 2000){

Toast. makeText (getApplicationContext(), \" 再按一次退出程序 Toast.

LENGTH_SHOR)T.show();

exitTime = System. currentTimeMillis ();

else { finish();

System. exit (0); }

return true ;

}

new

}

return super .onKeyDown(keyCode, event);

}

}

CollectionActivity.java

public class CollectionActivity extends ExpandableListActivity { @Override

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 一级条目

List>groups=new ArrayList>(); Map group1=new HashMap(); group1.put(\"group\

【歌手】 \");

Map group2=new HashMap(); group2.put(\"group\groups.add(group1); groups.add(group2); // 二组条目

List>> childs=new ArrayList>>();

【专辑】 \");

// 第一组二级科目数据

List> ArrayList>(); Map item1=new HashMap(); item1.put(\"child\

林俊杰 \");

Map item2=new HashMap(); item2.put(\"child\周杰伦 \");

child1.add(item1); child1.add(item2); // 第二组二级科目数据

List> ArrayList>(); Map item3=new HashMap(); item3.put(\"child\因你而在 >>\");

Map item4=new HashMap(); item4.put(\"child\

流行主教 >>\"); Map item5=new HashMap(); item5.put(\"child\第二天堂 >>\");

child2.add(item3); child2.add(item4); child2.add(item5); childs.add(child1);

child1=new

child2=new

childs.add(child2);

//SimpleExpandableListAdapter //1.content //2. //3. // //5. //6. //7. //8. //9.

一级条目数据 一级条目布局文件

构造函数参数

4 . 一级条目Key

一级条目显示信息控件 二级条目数据 二级条目布局文件 二级条目 Key 二级条目显示信息控件

id

id

setListAdapter(adapter); }

private long exitTime = 0;

public boolean onKeyDown(int keyCode, KeyEvent event) {

if(keyCode == KeyEvent.KEYCODE_BACK&& event.getAction()

KeyEvent.ACTION_DOWN){

if((System.currentTimeMillis()-exitTime) >

2000){ Toast.makeText(getApplicationContext(), \"

序\

再按一次退出程

exitTime = System.currentTimeMillis();

}

else { finish(); System.exit(0); }

return true; }

return super.onKeyDown(keyCode, event);

}

/**

* 初始化菜单 */

public boolean onMenuKeyDown(int keyCode, KeyEvent event)

{ if(keyCode==KeyEvent.KEYCODE_MENU&& event.getAction() =

KeyEvent.ACTION_DOWN){

Toast.makeText(getApplicationContext(), \" 未 定 义 菜 单 \"

Toast.LENGTH_SHORT).show();

}

return true; }

}

Contsant.java

public class Contsant {

*

获取屏幕的大小 0:宽度 1 :高度

**/

public static int[] getScreen(Context context) {

WindowManager windowManager

context.getSystemService(Context.WINDOW_SERVICE);

Display display = windowManager.getDefaultDisplay();

DisplayMetrics outMetrics = new DisplayMetrics(); display.getMetrics(outMetrics); return new int[] { (int) (outMetrics.density * outMetrics.widthPixels), (int)

(outMetrics.density * outMetrics.heightPixels) };

}

(WindowManager)

/**

获取文件的后缀名,返回大写

**/ public static String getSuffix(String str) {

int i = str.lastIndexOf('.'); if (i != -1) {

return str.substring(i + 1).toUpperCase(); } return str;

}

/**

格式化文件大小 Byte->MB **/

public static String formatByteToMB(int size){ float mb=size/1024f/1024f;

return String.format(\"%.2f\

LRCbean.java

package /** 歌词实体 */ public class LRCbean {

private int beginTime = 0; public int getBeginTime() {

return beginTime;

}

// 开始时间

public void setBeginTime( int beginTime) { this .beginTime = beginTime;

}

public int getLineTime() {

return lineTime;

}

public void setLineTime( int lineTime) { this .lineTime = lineTime;

}

public String getLrcBody() { return lrcBody; public void setLrcBody(String lrcBody) {

this .lrcBody = lrcBody;

}

private int lineTime = 0;

private String lrcBody = null ; // 歌词实体 }

MDialog.java

* 自定义的对话框 */

public class MDialog extends Dialog {

public MDialog(Context context) {

super(context);

}

public MDialog(Context context, int theme) { super(context, theme);

}

public static class Builder {

private Context context;

private int mIcon = -1; // private CharSequence mTitle; // private CharSequence mMessage;// private

CharSequence

CharSequence mCancelable = true;//

提示图标 提示标题 提示内容

private 确定按钮文本 private 拒绝按钮文本 是否启用取消键

mPositiveButtonText;//

mNegativeButtonText;//

CharSequence mNeutralButtonText; // private boolean 中间按钮文本

private int mViewSpacingLeft; private int mViewSpacingTop; private int mViewSpacingRight; private int mViewSpacingBottom;

private boolean mViewSpacingSpecified = false; // 提示内容 View

private View mView; private OnClickListener mPositiveButtonClickListener, mNegativeButtonClickListener, mNeutralButtonClickListener;

private OnCancelListener mCancelListener;// private OnKeyListener mKeyListener; //

取消键事件 按键处理

public Builder(Context context) {

this.context = context;

}

public Builder setMessage(CharSequence message) { this.mMessage = message;

return this;

}

public Builder setMessage(int message) { this.mMessage = context.getText(message);

return this;

}

public Builder setTitle(int title) {

this.mTitle = context.getText(title); return this;

}

public Builder setTitle(CharSequence title) {

this.mTitle = title; return this;

}

public Builder setIcon(int icon) {

this.mIcon = icon;

return this;

}

public Builder setView(View view) {

this.mView = view;

mViewSpacingSpecified = false; return this;

}

public Builder setView(View view, int left, int top, int right, int bottom) {

this.mView = view;

this.mViewSpacingLeft = left; this.mViewSpacingTop = top; this.mViewSpacingRight = right; this.mViewSpacingBottom = bottom; mViewSpacingSpecified = true; return this;

}

public Builder setPositiveButton(int textId,

final OnClickListener listener) { this.mPositiveButtonText = context.getText(textId); this.mPositiveButtonClickListener = listener; return this;

}

public Builder setPositiveButton(String text,

final OnClickListener listener) { this.mPositiveButtonText = text; this.mPositiveButtonClickListener = listener; return this;

}

public Builder setNeutralButton(int textId,

final OnClickListener listener) { this.mNeutralButtonText = context.getText(textId); this.mNeutralButtonClickListener = listener; return this;

}

public Builder setNeutralButton(String text,

final OnClickListener listener) { this.mNeutralButtonText = text; this.mNeutralButtonClickListener = listener; return this;

}

public Builder setNegativeButton(int textId,

final OnClickListener listener) { this.mNegativeButtonText = context.getText(textId); this.mNegativeButtonClickListener = listener; return this;

}

public Builder setNegativeButton(String text,

final OnClickListener listener) { this.mNegativeButtonText = text; this.mNegativeButtonClickListener = listener; return this;

}

public Builder setCancelable(boolean cancelable) { this.mCancelable = cancelable;

return this;

}

public Builder setOnCancelListener(OnCancelListener listener) { this.mCancelListener =

listener; return this;

}

public Builder setOnKeyListener(OnKeyListener listener) { this.mKeyListener = listener;

return this;

}

public MDialog create() {

LayoutInflater inflater = (LayoutInflater) context

.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

dialog.setCancelable(mCancelable); // 设置取消键事件

if (mCancelListener != null) {

dialog.setOnCancelListener(mCancelListener);

}

// 设置键盘监听事件

if (mKeyListener != null) { dialog.setOnKeyListener(mKeyListener);

}

// 获取对话框布局

layout.setLayoutParams(new

LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));

// 设置标题 // 设置图标 if (mIcon != -1) {

}

int count = 0; // 设置确定按钮

count++; // 设置拒绝按钮

count++; // 设置中间按钮

count++; if(count==0){

}

// 一个按钮时,显示两边空间 if (count == 1) {

}

// 设置提示消息

if (!TextUtils.isEmpty(mMessage)) { } else {

}

// 设置提示内容布局 if (mView != null) {

if (mViewSpacingSpecified) {

customPanel.setPadding(mViewSpacingLeft,

mViewSpacingTop,mViewSpacingRight, mViewSpacingBottom);

}

customPanel.addView(mView); } else {

}

dialog.setContentView(layout); return dialog;

}

public MDialog show() {

MDialog dialog = create();

dialog.show(); return dialog;

}

private boolean setButton(View layout, mPositiveButtonText2, int id,

final Dialog dialog, final OnClickListener listener) { if (!TextUtils.isEmpty(mPositiveButtonText2)) {

final Button button1 = (Button) layout.findViewById(id); button1.setText(mPositiveButtonText2); if (listener != null) {

button1.setOnClickListener(new View.OnClickListener()

{ public void onClick(View v) {

listener.onClick(dialog,DialogInterface.BUTTON_POSITIVE);

}

}); }else{

// 默认事件为关闭对话框 button1.setOnClickListener(new View.OnClickListener() { public void onClick(View v) {

dialog.cancel(); dialog.dismiss();

}

});

}

return true;

} else { layout.findViewById(id).setVisibility(View.GONE); return false;

}

}

}

}

MusicActivity.java

/* 以 Tabhost+RadioGroup 组合 */ public class MusicActivity extends TabActivity

OnCheckedChangeListener{

private TabHost tabhost; private RadioGroup radiogroup; @Override

CharSequence

implements

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

requestWindowFeature(Window.FEATURE_NO_TITLE); tabhost=getTabHost(); radiogroup.setOnCheckedChangeListener(this); radiogroup.setClickable(true);

tabhost.addTab(tabhost.newTabSpec(\"local_music\").setIndicator(\"local_musi c\").setContent(new Intent(this,MusicListActivity.class)));

tabhost.addTab(tabhost.newTabSpec(\"my_collect\").setIndicator(\"my_collect\" ).setContent(new Intent(this,CollectionActivity.class)));

tabhost.addTab(tabhost.newTabSpec(\"net_music\").setIndicator(\"net_music\"). setContent(new Intent(this,NetMusicActivity.class)));

}

@Override

public void onCheckedChanged(RadioGroup group, int checkedId) { switch (checkedId) { tabhost.setCurrentTabByTag(\"local_music\");

break; tabhost.setCurrentTabByTag(\"my_collect\"); break; tabhost.setCurrentTabByTag(\"net_music\"); break;

}

}

}

MusicListActivity.java

public class MusicListActivity extends Activity {

/** 音乐列表 **/

private ListView listview; private String musicpath; private int _ids[]; // private String _titles[]; // private String _artists[]; // private String[] _path; // private String[] _times; // private String[] _album; // private int _sizes[]; // private String[] _displayname;// private int num; //num private LayoutInflater inflater;//

存放音乐文件的 id 数组 存放音乐文件的标题数组 存放音乐艺术家的标题数组 存放音乐路过的标题数组 存放总时间的标题数组 存放专辑的标题数组 存放文件大小的标题数组 存放名称的标题数组

确定一个标识 装载布局

private LayoutParams params; private Toast toast; // 提示 public static final int Ringtone = 0; public static final int Alarm = 1; public static final int Notification = 2; private TextView timers;// 显示倒计时的文字 public MusicListAdapter adapter; @Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

/** 选择子项点击事件 ***/ listview.setOnItemClickListener(new MusicListOnClickListener()); listview.setOnCreateContextMenuListener(new

MusicListContextListener());

inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); params = new

LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT);

ShowMp3List();

}

/**显示MP3信息,其中」ds保存了所有音乐文件的_ID,用来确定到底要播放哪一首歌 曲,

_titles 存放音乐名,用来显示在播放界面,

_path 存放音乐文件的路径(删除文件时会用到) private void ShowMp3List() { /** 用游标查找媒体详细信息 **/

Cursor cursor = this.getContentResolver().query(

/** 判断游标是否为空,有些地方即使没有音乐也会报异常。而且游标不稳定。稍有 不慎就出

错了 , 其次,如果用户没有音乐的话,不妨可以告知用户没有音乐让用户添加进去 */

if (cursor!= null && cursor.getCount() == 0) {

final

MDialog

xfdialog

=

new

。**/

MDialog.Builder(MusicListActivity.this).setTitle(\" 未找到音乐 , 请添加音乐 \").setPositiveButton(\"

xfdialog.show(); return;

}

提示 :\").setMessage(\" 你的手机

确定 \", null).create();

/** 将游标移到第一位 **/ cursor.moveToFirst();

/** 分别将各个标题数组实例化 **/ _ids = new int[cursor.getCount()];// _titles = new String[cursor.getCount()]; _artists = new String[cursor.getCount()]; _path = new String[cursor.getCount()]; _album = new String[cursor.getCount()]; _times = new String[cursor.getCount()];

_displayname = new String[cursor.getCount()]; _sizes = new int[cursor.getCount()];

到的内容格式为 /mnt/sdcard/[ 子文件夹名 /] 音乐文件名, 的是

而我们想要得到

/sdcard/[ 子文件夹名 ] 音乐文件名

**/

for (int i = 0; i < cursor.getCount(); i++) {

_ids[i] = cursor.getInt(3); _titles[i] = cursor.getString(0);

_artists[i] = cursor.getString(2); _path[i] = cursor.getString(5).substring(4);

/** 以下是为提供音乐详细信息而生成的 **/ _album[i] = cursor.getString(7); _times[i] = toTime(cursor.getInt(1)); _sizes[i] = cursor.getInt(8);

_displayname[i] = cursor.getString(4);

cursor.moveToNext(); /** 一直将游标往下走 **/

}

listview.setAdapter(new MusicListAdapter(this, cursor));

}

/** 时间的转换 **/

public String toTime(int time) {

time /= 1000; int minute = time / 60; int second = time % 60; minute %= 60;

/** 返回结果用 string 的 format 方法把时间转换成字符类型 **/ return String.format(\"%02d:%02d\

}

/** 音乐列表添加监听器,点击之后播放音乐 */ public class

MusicListOnClickListener implements OnItemClickListener { @Override

public void onItemClick(AdapterView arg0, View view, long id) {

playMusic(position);

}

}

/** 长按 Listview 后弹出菜单 **/ private class MusicListContextListener

OnCreateContextMenuListener {

@Override

public void onCreateContextMenu(ContextMenu v,ContextMenuInfo info)

{

SongItemDialog();

/** 当 显 示 AdapterView 的 上 下 文 菜 单 时 , 为

onCreateContextMenu(ContextMenu, View, ContextMenuInfo) 回调函数提供的额外的菜单 信息 .**/

final AdapterView.AdapterContextMenuInfo menuInfo =

(AdapterView.AdapterContextMenuInfo) info;

int position,

implements

menu, View

num = menuInfo.position;

}

}

/** 根据 Position 播放音乐 **/ public void playMusicII(int position) { musicpath=\"/mnt\"+_path[position]; try{

MediaPlayer mp = new MediaPlayer(); mp.reset();

mp.setDataSource(musicpath); mp.prepare(); mp.start(); }catch(Exception e){

Toast.makeText(getApplicationContext(),\" 无 法 播 放 此 文 件 \

Toast.LENGTH_SHORT).show();

}

}

/** 根据 Position 播放音乐 **/ public void playMusic(int position) {

Intent intent = new Intent(MusicListActivity.this,PlayMusicActivity.class);

intent.putExtra(\"_ids\_artists); intent.putExtra(\"_path\intent.putExtra(\"position\finish();

}

/** 用户长按列表或者按住最右边的倒三角形发生的事件 **/ private void SongItemDialog() {

String[] menustring = new String[] { \" 播放选中音乐 \收藏选中音乐 \查看歌曲信息 \" ,\" 删

除选中歌曲 \

ListView menulist = new ListView(MusicListActivity.this);

menulist.setCacheColorHint(Color.TRANSPARENT); menulist.setDividerHeight(1); menulist.setLayoutParams(new

LayoutParams(Contsant.getScreen(MusicListActivity.this)[0] /

2,LayoutParams.WRAP_CONTENT));

xfdialog.show();

menulist.setOnItemClickListener(new OnItemClickListener() {

@Override

public void onItemClick(AdapterView parent, View view,int position, long id) {

xfdialog.cancel(); xfdialog.dismiss(); if (position==0) { playMusic(num); }else if (position==1) {

CollectMusic(num); }else if (position==2) {

ShowMusicInfo(num); }else if (position==3) {

DeleteMusic(num);

}

}

});

}

private void ShowMusicInfo(int location) {

}

private void CollectMusic(int location){

Toast.makeText(getApplicationContext(), \" 收 藏 成 功 Toast.LENGTH_SHORT).show();

}

private void DeleteMusic(int location){

Toast.makeText(getApplicationContext(), \" 删 除 成 功 Toast.LENGTH_SHORT).show();

}

/** 退出程序方法 **/

private long exitTime = 0;

public boolean onKeyDown(int keyCode, KeyEvent event) {

if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction()

KeyEvent.ACTION_DOWN){

if((System.currentTimeMillis()-exitTime) > 2000){

Toast.makeText(getApplicationContext(), \"

\

exitTime = System.currentTimeMillis();

}

再按一次退出程序

else { finish(); System.exit(0);

}

return true; }

return super.onKeyDown(keyCode, event); }

}

NetMusicActivity.java

/* 以 Tabhost+RadioGroup 组合 */ public class NetMusicActivity OnCheckedChangeListener{

private TabHost tabhost; private RadioGroup radiogroup; @Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

requestWindowFeature(Window.FEATURE_NO_TITLE); tabhost=getTabHost(); radiogroup.setOnCheckedChangeListener(this); radiogroup.setClickable(true);

tabhost.addTab(tabhost.newTabSpec(\"bangdan\").setIndicator(\"bangdan\").setC ontent(new Intent(this,SingerActivity.class)));

tabhost.addTab(tabhost.newTabSpec(\"tuijian\").setIndicator(\"tuijian\").setC ontent(new Intent(this,SingerActivity.class)));

tabhost.addTab(tabhost.newTabSpec(\"gedan\").setIndicator(\"gedan\").setConte nt(new Intent(this,SingerActivity.class)));

tabhost.addTab(tabhost.newTabSpec(\"geshou\").setIndicator(\"geshou\").setCon tent(new Intent(this,SingerActivity.class)));

tabhost.addTab(tabhost.newTabSpec(\"diantai\").setIndicator(\"diantai\").setC ontent(new Intent(this,SingerActivity.class)));

}

extends TabActivity

implements

@Override

public void onCheckedChanged(RadioGroup group, int checkedId) { switch (checkedId) {

tabhost.setCurrentTabByTag(\"bangdan\"); break;

tabhost.setCurrentTabByTag(\"tuijian\"); break;

tabhost.setCurrentTabByTag(\"gedan\"); tabhost.setCurrentTabByTag(\"geshou\");

/** 播放音乐界面 **/ public class PlayMusicActivity extends Activity { private

RelativeLayout ll_player_voice; private

RelativeLayout music_all; private int[] _ids; // private String[] _artists; // private String[]

_titles; // private String[]_album; // private

tabhost.setCurrentTabByTag(\"diantai\");

break;

PlayMusicActivity.java

临时音乐 id 艺术家 标题

TextView musicnames; // private TextView 专辑 音乐名 artisting; // private ImageButton play_btn;// 艺术家 播放private ImageButton last_btn;// private playtimes = null;

按钮 上一首

ImageButton next_btn;// private TextView 下一首

//

private TextView durationTime = null;// private SeekBar seekbar;

//

private SeekBar sp_player_voice;// private int position; // private int currentPosition;// private int duration; // private ImageView album; // private ImageButton LoopBtn = null; private ImageButton RandomBtm = null; private ImageButton ibtn_player_list;

//

已播放时间 歌曲时间 进度条 调节音量

定义一个位置, 用于定位用户点击列表曲首 当前播放位置 总时间 专辑 //

循环 随机

private ImageButton ibtn_player_control_menu; private static final int PLAY = 1; // private static final int PAUSE = 2; // private static final int STOP = 3; // private static final int PROGRESS_CHANGE = 4;// private static final int STATE_PLAY = 1; // private static final int STATE_PAUSE = 2; // public static final int LOOP_NONE = 0; // public static final int LOOP_ONE = 1; // public static final int LOOP_ALL = 2; // public static int loop_flag = LOOP_NONE; public static boolean random_flag = false; public static int[] randomIDs = null;

不循环 单体循环 全部循环 定义播放状态 暂停状态 停止

进度条改变 播放状态设为 1 暂停状态设为 2

public static int randomNum = 0; private int flag; // private Cursor cursor;// private AudioManager am; private int maxVolume; // private int currentVolume;//

最大音量 当前音量 标记 游标

private ImageButton ibtn_player_voice;// 右上角的音量图标 private Toast toast; // private Context context;//

提示消息 上下文

private TreeMap lrc_map = new TreeMap();// Treemap 对

// 音量面板显示和隐藏动画

private Animation showVoicePanelAnimation; private Animation hiddenVoicePanelAnimation; @Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

requestWindowFeature(Window.FEATURE_NO_TITLE); // 以下是找各个控件 ID

ibtn_player_voice.setOnClickListener(listener);

sp_player_voice.setOnSeekBarChangeListener(seekBarChangeListener); am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); maxVolume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); currentVolume = am.getStreamVolume(AudioManager.STREAM_MUSIC); context=this; // 获取系统音乐音量

am = (AudioManager)getSystemService(Context.AUDIO_SERVICE); // 获取系统音乐当前音量

int currentVolume = am.getStreamVolume(AudioManager.STREAM_MUSIC); ibtn_player_list.setOnClickListener(listeners);

ibtn_player_control_menu.setOnClickListener(listeners); ShowPlayBtn(); ShowLastBtn(); ShowNextBtn(); ShowSeekBar();

}

/** 显示播放按钮并做监听 **/ private void ShowPlayBtn() {

play_btn.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

switch (flag) { case STATE_PLAY:

pause(); break;

case STATE_PAUSE:

play(); break;

}

}

});

}

private void ShowLastBtn() {

last_btn.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

lastOne();

}

});

}

private void ShowNextBtn() {

next_btn.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

nextOne();

}

});

}

private void ShowSeekBar() {

seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override

public void onStopTrackingTouch(SeekBar seekBar) {} @Override

public void onStartTrackingTouch(SeekBar seekBar) {} @Override

public void onProgressChanged(SeekBar seekBar, int progress,

boolean fromUser) { if (fromUser) {

seekbar_change(progress);

// 设置音量 am.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0);

}

}

});

}

/** 顺序播放 **/

private void ShowLoop() {

LoopBtn.setOnClickListener(new OnClickListener() { @Override

public void onClick(View v) { switch (loop_flag) { case LOOP_NONE:

loop_flag = LOOP_ONE; break; case LOOP_ALL:

loop_flag = LOOP_NONE; break; case LOOP_ONE:

loop_flag = LOOP_ALL; break;

}

}

});

}

/** 按随机播放 **/

private void ShowRandom() {

RandomBtm.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) { if (random_flag==false) {

for (int i = 0; i < _ids.length; i++) {

randomIDs[i] = -1;

}

random_flag=true; }else {

random_flag=false; }

}

});

}

/** 在播放布局里先把播放按钮先删除并用 background 设置为透明。

钮**/

public void play() {

flag = PLAY;

Intent intent = new Intent(); intent.putExtra(\"op\startService(intent);

}

然后在代码添加按

向服务传递数据

/** 暂停 **/

public void pause() {

flag = PAUSE;

Intent intent = new Intent(); intent.putExtra(\"op\/** 上一首 **/ private void lastOne() {

if (_ids.length == 1 || loop_flag == LOOP_ONE) { position = position;

Intent intent = new Intent(); intent.putExtra(\"length\play(); return;

}

if (random_flag == true) {

if (randomNum < _ids.length - 1) { randomIDs[randomNum] = position; position =

findRandomSound(_ids.length); randomNum++;

}

else {

randomNum = 0;

for (int i = 0; i < _ids.length; i++) { randomIDs[i] = -1;

}

randomIDs[randomNum] = position; position = findRandomSound(_ids.length);

randomNum++;

}

}

else {

if (position == 0) { position = _ids.length - 1;

}

else if (position > 0) { position--;

}

}

stop(); setup(); play();

}

/** 进度条改变事件 **/

private void seekbar_change(int progress) {

Intent intent = new Intent(); intent.putExtra(\"op\intent.putExtra(\"progress\startService(intent);

/** 下一首 **/ public void nextOne() {

if (_ids.length == 1 || loop_flag == LOOP_ONE)

{ position = position; Intent intent = new Intent();

intent.putExtra(\"length\play(); return;

}

if (random_flag == true) {

if (randomNum < _ids.length - 1)

{ randomIDs[randomNum] = position; position = findRandomSound(_ids.length); randomNum++;

}

else {

randomNum = 0;

for (int i = 0; i < _ids.length; i++)

{ randomIDs[i] = -1;

}

randomIDs[randomNum] = position;

position = findRandomSound(_ids.length); randomNum++;

}

}

else {

if (position == _ids.length - 1) { position = 0;

}

else if (position < _ids.length - 1) { position++;

}

}

stop(); setup(); play();

}

/** 找到随机位置 **/

public static int findRandomSound(int end) { int ret = -1;

ret = (int) (Math.random() * end); while (havePlayed(ret, end)) { ret = (int) (Math.random() *

常 **/

\"...\");//

end);

}

return ret;

}

/** 是否在播放 **/ public static boolean havePlayed(int

position, int num) { boolean ret = false;

for (int i = 0; i < num; i++) { if (position == randomIDs[i]) { ret = true; break;

} }

return ret;

}

/** 停止播放音乐 **/ private void stop() {

Intent isplay = new Intent(\"notifi.update\"); sendBroadcast(isplay);// 发起后台支持 unregisterReceiver(musicReceiver);

Intent intent = new Intent(); intent.putExtra(\"op\

}

protected void onResume() { super.onResume();

Intent intent = this.getIntent();// 接收来自列表的数据

Bundle bundle = intent.getExtras();

_ids = bundle.getIntArray(\"_ids\"); randomIDs = new int[_ids.length]; position = bundle.getInt(\"position\");

_titles = bundle.getStringArray(\"_titles\"); _artists = bundle.getStringArray(\"_artists\"); _album = bundle.getStringArray(\"_album\"); setup(); play();

ShowLoop(); ShowRandom();

}

/** 当界面不可见时候,反注册的广播 **/

protected void onStop() { super.onStop(); unregisterReceiver(musicReceiver);

}

/** 初始化 **/ private void setup() { loadclip(); init();

}

/** 在顶部显示歌手,歌名。这两个是通过服务那边接收过来的 , 如果其中一个不写直接 空指针异

private void loadclip() { seekbar.setProgress(0);

/** 设置歌曲名 **/

if (_titles[position].length() > 15) musicnames.setText(_titles[position].substring(0, 12) +

设置歌曲名

else musicnames.setText(_titles[position]); /** 设置艺术家名 **/

if (_artists[position].equals(\"\")) artisting.setText(\" 未知艺术家 \"); else artisting.setText(_artists[position]);

Intent intent = new Intent(); intent.putExtra(\"_ids\intent.putExtra(\"_artists\

}

/** 初始化 **/ private void init() {

IntentFilter filter = new IntentFilter(); filter.addAction(MUSIC_CURRENT); filter.addAction(MUSIC_DURATION); filter.addAction(MUSIC_NEXT); filter.addAction(MUSIC_UPDATE); filter.addAction(\"notifi.update\");

registerReceiver(musicReceiver, filter);

}

/** 在后台 MusicService 里使用 handler 消息机制, 不停的向前台发送广播, 广播里面 的数据是

当前 mp 播放的时间点,

* 前台接收到广播后获得播放时间点来更新进度条 , 暂且先这样。 但是一些人说虽然这样

能实现。但是还是觉得开个子线程不错 **/

protected BroadcastReceiver musicReceiver = new BroadcastReceiver() {

public void onReceive(Context context, Intent intent) {

String action = intent.getAction(); if (action.equals(MUSIC_CURRENT)) {

currentPosition

intent.getExtras().getInt(\"currentTime\");// 获得当前播放位置 playtimes.setText(toTime(currentPosition));

seekbar.setProgress(currentPosition);// 设置进度条 } else if (action.equals(MUSIC_DURATION)) {

duration = intent.getExtras().getInt(\"duration\"); seekbar.setMax(duration); durationTime.setText(toTime(duration)); } else if (action.equals(MUSIC_NEXT)) { nextOne(); } else if (action.equals(MUSIC_UPDATE)) {

position = intent.getExtras().getInt(\"position\"); setup();

}

}

};

/** 播放时间转换 **/

public String toTime(int time) {

time /= 1000; int minute = time / 60; int second = time % 60; minute %= 60;

return String.format(\"%02d:%02d\

}

/** 暂时为音量调整大小 **/

private OnSeekBarChangeListener seekBarChangeListener OnSeekBarChangeListener() {

@Override

public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

// 设置音量 am.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0);

}

}

new

@Override

public void onStartTrackingTouch(SeekBar arg0) {

}

@Override

public void onStopTrackingTouch(SeekBar arg0) {

}

};

/** 小图标的监听事件 **/

private OnClickListener listener = new OnClickListener() {

@Override

public void onClick(View v) {

switch (v.getId()) {

voicePanelAnimation(); break; finish(); break;

}

}

};

/** 音量面板显示和隐藏 **/ private void voicePanelAnimation() {

if (ll_player_voice.getVisibility() == View.GONE)

{ ll_player_voice.startAnimation(showVoicePanelAnimation); ll_player_voice.setVisibility(View.VISIBLE);

}

else {

ll_player_voice.startAnimation(hiddenVoicePanelAnimation); ll_player_voice.setVisibility(View.GONE);

}

}

/** 回调音量大小函数 **/

public boolean dispatchKeyEvent(KeyEvent event) {

int action = event.getAction(); int keyCode = event.getKeyCode(); switch (keyCode) {

case KeyEvent.KEYCODE_VOLUME_UP:

if (action == KeyEvent.ACTION_UP) {

if (currentVolume < maxVolume) { currentVolume = currentVolume + 1; am.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0); } else { am.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0);

}

}

return false;

case KeyEvent.KEYCODE_VOLUME_DOWN:

if (action == KeyEvent.ACTION_UP) {

if

(currentVolume

>

0)

{

currentVolume

=

currentVolume

-

1;

am.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0); } else { am.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0);

}

}

return false; default:

return super.dispatchKeyEvent(event);

}

}

/** 按下返回键事件 **/

public boolean onKeyDown(int keyCode, KeyEvent event) {

if (keyCode == KeyEvent.KEYCODE_BACK) {

Intent intent = new Intent(PlayMusicActivity.this,MusicActivity.class); startActivity(intent); finish(); finish();

}

return true;

}

private OnClickListener listeners = new OnClickListener(){

@Override

public void onClick(View view) {

switch (view.getId()) {

Intent intent=new Intent(PlayMusicActivity.this,MusicActivity.class); startActivity(intent); finish(); break;

String[] menustring = new String[] { \" ListView

menulist

=

new

搜索歌词 \睡眠模式 \" }; ListView(PlayMusicActivity.this);

menulist.setCacheColorHint(Color.TRANSPARENT); menulist.setDividerHeight(1); menulist.setLayoutParams(new

LayoutParams(Contsant.getScreen(PlayMusicActivity.this)[0] 2,LayoutParams.WRAP_CONTENT));

/

final MDialog

MDialog.Builder(PlayMusicActivity.this).setTitle(\"

xfdialog

=

系 统

new

作 :\").setView(menulist).create();

xfdialog.show(); break;

}

}

};

/** 为音乐读取歌词,歌词一行一行方式输出 **/ private

void ReadSDLrc() {

/** 我们现在的歌词就是要 String 数组的第 4 个参数 - 显示文件名字 **/ \"_id=?\

new String[] { _ids[position] + \"\" }, null); cursor.moveToFirst();// 将游标移至第一

}

}

AndroidMainfest.xml

package =

android:versionCode =\"1\" android:versionName =\"1.0\" > android:minSdkVersion =\"8\" android:targetSdkVersion =\"19\" /> android:name =

android:label =\"@string/app_name\"

android:name =

android:label

=\"@string/title_activity_music\"

android:name =

android:label =\"@string/title_activity_collection\"

android:name =

android:label =\"@string/title_activity_music_list\"

android:name =

android:label =\"@string/title_activity_net_music\"

android:name =

android:label =\"@string/title_activity_play_music\"

android:name =

android:label =\"@string/title_activity_bangdan\"

android:name =

android:label =\"@string/title_activity_singer\"

android:name =

android:label

=\"@string/title_activity_system_setting\"

>

>

>

>

>

>

>

>

因篇幅问题不能全部显示,请点此查看更多更全内容