1、获取音乐
1-1:获取手机中的音乐(用ContentProvider内容提供者来完成):
1 package com.firefly.util;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.Iterator;
6 import java.util.List;
7
8 import android.content.Context;
9 import android.database.Cursor;
10 import android.provider.MediaStore;
11 import android.util.Log;
12
13 public class MediaUtil {
14 /**
15 * 用于从数据库中查询歌曲的信息,保存在List当中
16 *
17 * @return
18 */
19 public static List<Mp3Info> getMp3Infos(Context context) {
20 Cursor cursor = context.getContentResolver().query(
21 MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
22 MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
23 List<Mp3Info> mp3Infos = new ArrayList<Mp3Info>();
24
25 for (int i = 0; i < cursor.getCount(); i++) {
26 cursor.moveToNext();
27 Mp3Info mp3Info = new Mp3Info();
28 long id = cursor.getLong(cursor
29 .getColumnIndex(MediaStore.Audio.Media._ID)); // 音乐id
30 String title = cursor.getString((cursor
31 .getColumnIndex(MediaStore.Audio.Media.TITLE))); // 音乐标题
32 String artist = cursor.getString(cursor
33 .getColumnIndex(MediaStore.Audio.Media.ARTIST)); // 艺术家
34 long duration = cursor.getLong(cursor
35 .getColumnIndex(MediaStore.Audio.Media.DURATION)); // 时长
36 long size = cursor.getLong(cursor
37 .getColumnIndex(MediaStore.Audio.Media.SIZE)); // 文件大小
38 String url = cursor.getString(cursor
39 .getColumnIndex(MediaStore.Audio.Media.DATA)); // 文件路径
40 int isMusic = cursor.getInt(cursor
41 .getColumnIndex(MediaStore.Audio.Media.IS_MUSIC)); // 是否为音乐
42 if (isMusic != 0) { // 只把音乐添加到集合当中
43
44 mp3Info.setId(id);
45 mp3Info.setTitle(title);
46 mp3Info.setArtist(artist);
47 mp3Info.setDuration(duration);
48 mp3Info.setSize(size);
49 mp3Info.setUrl(url);
50
51 mp3Infos.add(mp3Info);
52 }
53 }
54 return mp3Infos;
55 }
56
57 /**
58 * 格式化时间,将毫秒转换为分:秒格式
59 *
60 * @param time
61 * @return
62 */
63 public static String formatTime(long time) {
64 String min = time / (1000 * 60) + "";
65 String sec = time % (1000 * 60) + "";
66 if (min.length() < 2) {
67 min = "0" + time / (1000 * 60) + "";
68 } else {
69 min = time / (1000 * 60) + "";
70 }
71 if (sec.length() == 4) {
72 sec = "0" + (time % (1000 * 60)) + "";
73 } else if (sec.length() == 3) {
74 sec = "00" + (time % (1000 * 60)) + "";
75 } else if (sec.length() == 2) {
76 sec = "000" + (time % (1000 * 60)) + "";
77 } else if (sec.length() == 1) {
78 sec = "0000" + (time % (1000 * 60)) + "";
79 }
80 return min + ":" + sec.trim().substring(0, 2);
81 }
82 }
MediaUtil
1-2:写实体类来存放获取的音乐数据
1 package com.firefly.util;
2
3 public class Mp3Info {
4 public long id; // 音乐id
5 public String title;// 音乐标题
6 public String artist;// 艺术家
7 public long duration; // 时长
8 public long size;// 文件大小
9 public String url;// 文件路径
10 public int isMusic;// 是否为音乐
11
12 public long getId() {
13 return id;
14 }
15
16 public void setId(long id) {
17 this.id = id;
18 }
19
20 public String getTitle() {
21 return title;
22 }
23
24 public void setTitle(String title) {
25 this.title = title;
26 }
27
28 public String getArtist() {
29 return artist;
30 }
31
32 public void setArtist(String artist) {
33 this.artist = artist;
34 }
35
36 public long getDuration() {
37 return duration;
38 }
39
40 public void setDuration(long duration) {
41 this.duration = duration;
42 }
43
44 public long getSize() {
45 return size;
46 }
47
48 public void setSize(long size) {
49 this.size = size;
50 }
51
52 public String getUrl() {
53 return url;
54 }
55
56 public void setUrl(String url) {
57 this.url = url;
58 }
59
60 public int getIsMusic() {
61 return isMusic;
62 }
63
64 public void setIsMusic(int isMusic) {
65 this.isMusic = isMusic;
66 }
67
68 }
Mp3Info
1-3:写适配器来将音乐数据初始化
1 package com.firefly.util;
2
3 import java.util.List;
4
5 import com.firefly.beautifulmusic.R;
6
7 import android.content.Context;
8 import android.graphics.Color;
9 import android.view.LayoutInflater;
10 import android.view.View;
11 import android.view.ViewGroup;
12 import android.widget.BaseAdapter;
13 import android.widget.TextView;
14
15 public class MusicAdapter extends BaseAdapter {
16 List<Mp3Info> datas;
17 LayoutInflater inflater;
18 int index = -1;
19
20 // 把当前位置传过来
21 public void setIndex(int index) {
22 this.index = index;
23 }
24
25 public MusicAdapter(Context context, List<Mp3Info> datas) {
26 this.inflater = LayoutInflater.from(context);
27 this.datas = datas;
28 }
29
30 @Override
31 public int getCount() {
32 // TODO Auto-generated method stub
33 return datas.size();
34 }
35
36 @Override
37 public Object getItem(int position) {
38 // TODO Auto-generated method stub
39 return datas.get(position);
40 }
41
42 @Override
43 public long getItemId(int position) {
44 // TODO Auto-generated method stub
45 return position;
46 }
47
48 @Override
49 public View getView(int position, View convertView, ViewGroup parent) {
50 ViewHolder holder;
51 if (convertView == null) {
52 convertView = inflater.inflate(R.layout.item_music_list, null);
53 holder = new ViewHolder();
54 holder.title = (TextView) convertView.findViewById(R.id.item_title);
55 holder.duration = (TextView) convertView
56 .findViewById(R.id.item_duration);
57 holder.artist = (TextView) convertView
58 .findViewById(R.id.item_artist);
59 convertView.setTag(holder);
60 } else {
61 holder = (ViewHolder) convertView.getTag();
62 }
63 Mp3Info music = datas.get(position);
64 holder.title.setTag(music);
65 holder.title.setText(music.getTitle());
66 holder.artist.setText(music.getArtist());
67 // 获取时间并改变它的格式
68 Long time = music.getDuration();
69 long min = (time / 1000) / 60;
70 long second = (time / 1000) % 60;
71 holder.duration.setText(min + ":" + second);
72 if (position == index) {
73 // 如果正在播放当前项,就改其颜色
74 holder.title.setTextColor(Color.parseColor("#E34C36"));
75 holder.duration.setTextColor(Color.parseColor("#E34C36"));
76 holder.artist.setTextColor(Color.parseColor("#E34C36"));
77 } else {
78 // 否则的话则回到原来的状态
79 holder.title.setTextColor(Color.BLACK);
80 holder.duration.setTextColor(Color.BLACK);
81 holder.artist.setTextColor(Color.BLACK);
82 }
83 return convertView;
84 }
85
86 static class ViewHolder {
87 public TextView title;
88 public TextView duration;
89 public TextView artist;
90 }
91
92 }
MusicAdapter
1-4:(可不参考)用来适配的素材xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:orientation="horizontal" >
6
7 <LinearLayout
8 android:layout_width="match_parent"
9 android:layout_height="match_parent"
10 android:layout_weight="1"
11 android:orientation="vertical" >
12
13 <TextView
14 android:id="@+id/item_title"
15 android:layout_width="match_parent"
16 android:layout_height="wrap_content"
17 android:text="歌名" />
18
19 <TextView
20 android:id="@+id/item_artist"
21 android:layout_width="match_parent"
22 android:layout_height="wrap_content"
23 android:text="歌手" />
24 </LinearLayout>
25
26 <TextView
27 android:id="@+id/item_duration"
28 android:layout_width="match_parent"
29 android:layout_height="match_parent"
30 android:layout_weight="4"
31 android:text="时长" />
32
33 </LinearLayout>
item_music_list
2、在主页面中进行初始化数据
2-1:xml页面布局
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:orientation="vertical"
6 tools:context="${relativePackage}.${activityClass}" >
7
8 <ListView
9 android:id="@+id/lv_musicList"
10 android:layout_width="match_parent"
11 android:layout_height="match_parent"
12 android:layout_weight="1" >
13 </ListView>
14
15 <LinearLayout
16 android:layout_width="match_parent"
17 android:layout_height="wrap_content"
18 android:gravity="center"
19 android:orientation="horizontal" >
20
21 <Button
22 android:id="@+id/btnUp"
23 android:layout_width="50dp"
24 android:layout_height="50dp"
25 android:background="@drawable/up"
26 android:onClick="playMusic" />
27
28 <Button
29 android:id="@+id/btnPlay"
30 android:layout_width="50dp"
31 android:layout_height="50dp"
32 android:layout_marginLeft="20dp"
33 android:layout_marginRight="20dp"
34 android:background="@drawable/pause"
35 android:onClick="playMusic" />
36
37 <Button
38 android:id="@+id/btnDown"
39 android:layout_width="50dp"
40 android:layout_height="50dp"
41 android:background="@drawable/down"
42 android:onClick="playMusic" />
43 </LinearLayout>
44
45 <SeekBar
46 android:id="@+id/sb"
47 android:layout_width="match_parent"
48 android:layout_height="wrap_content" />
49
50 </LinearLayout>
activity_main
2-2:在其相对应的Activiity文件中初始化数据
1 package com.firefly.beautifulmusic;
2
3 import java.io.File;
4 import java.util.List;
5
6 import android.app.Activity;
7 import android.content.BroadcastReceiver;
8 import android.content.ComponentName;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.content.IntentFilter;
12 import android.content.ServiceConnection;
13 import android.graphics.Color;
14 import android.os.Bundle;
15 import android.os.IBinder;
16 import android.telephony.TelephonyManager;
17 import android.util.Log;
18 import android.view.View;
19 import android.widget.AdapterView;
20 import android.widget.AdapterView.OnItemClickListener;
21 import android.widget.Button;
22 import android.widget.ListView;
23 import android.widget.SeekBar;
24 import android.widget.TextView;
25 import android.widget.Toast;
26
27 import com.firefly.service.MusicService;
28 import com.firefly.service.MusicService.MyBinder;
29 import com.firefly.util.MediaUtil;
30 import com.firefly.util.Mp3Info;
31 import com.firefly.util.MusicAdapter;
32
33 public class MainActivity extends Activity {
34 ServiceConnection conn;
35 MusicService ms;
36 String music_name;
37 File f;
38 Boolean isPlay = false;
39 ListView lv;
40 MusicAdapter adapter;
41 List<Mp3Info> datas;
42 Button btn;
43 int current;
44 SeekBar sb;
45
46 @Override
47 protected void onCreate(Bundle savedInstanceState) {
48 super.onCreate(savedInstanceState);
49 setContentView(R.layout.activity_main);
50 //初始化数据
51 init();
52 }
53
54 private void init() {
55 btn = (Button) findViewById(R.id.btnPlay);
56 lv = (ListView) findViewById(R.id.lv_musicList);
57 //获取手机中 的音乐数据
58 datas = MediaUtil.getMp3Infos(MainActivity.this);
59 sb = (SeekBar) findViewById(R.id.sb);
60 adapter = new MusicAdapter(MainActivity.this, datas);
61 lv.setAdapter(adapter);
62 lv.setOnItemClickListener(new OnItemClickListener() {
63 @Override
64 public void onItemClick(AdapterView<?> parent, View view,
65 int position, long id) {
66 //点击哪一项就播放哪一项(前提条件是它是音乐文件)
67 current = position;
68 f = new File(datas.get(current).getUrl());
69 if (f.exists() && f.length() > 0) {
70 play();
71 } else {
72 Toast.makeText(getApplicationContext(), "该文件不是音乐", 0)
73 .show();
74 }
75 }
76 });
77 // 注册广播
78 broadcast();
79 // 服务
80 service();
81 }
82
83 private void broadcast() {
84 // TODO Auto-generated method stub
85 MusicBroadcast mb = new MusicBroadcast();
86 IntentFilter ifilter = new IntentFilter();
87 ifilter.addAction("com.firefly.music");
88 ifilter.addAction("android.intent.action.PHONE_STATE");
89 registerReceiver(mb, ifilter);
90 Log.e("TAG", "动态注册成功");
91 }
92
93 private void service() {
94 // TODO Auto-generated method stub
95 conn = new ServiceConnection() {
96
97 @Override
98 public void onServiceDisconnected(ComponentName name) {
99 // TODO Auto-generated method stub
100
101 }
102
103 @Override
104 public void onServiceConnected(ComponentName name, IBinder service) {
105 // TODO Auto-generated method stub
106 MyBinder binder = (MyBinder) service;
107 ms = binder.getService();
108 ms.setSeekBar(sb);
109 }
110 };
111
112 // 绑定服务
113 Intent i = new Intent(this, MusicService.class);
114 bindService(i, conn, BIND_AUTO_CREATE);
115 }
116
117 public void playMusic(View v) {
118 switch (v.getId()) {
119 case R.id.btnPlay:
120 if (isPlay == false) {
121 play();
122 } else {
123 pause();
124 }
125 break;
126 // 上一首
127 case R.id.btnUp:
128 if (isPlay) {
129 if ((current - 1) >= 0) {
130 --current;
131 f = new File(datas.get(current).getUrl());
132 play();
133 } else {
134 Toast.makeText(getApplicationContext(), "已经是第一首了", 0).show();
135 }
136 }
137 break;
138 // 下一首
139 case R.id.btnDown:
140 if ((current + 1) < datas.size()) {
141 ++current;
142 f = new File(datas.get(current).getUrl());
143 play();
144 } else {
145 Toast.makeText(getApplicationContext(), "已经是最后一首了", 0).show();
146 }
147 break;
148
149 default:
150 break;
151 }
152 }
153
154 //播放
155 public void play() {
156 //调用服务中的播放方法
157 ms.PlayMusic(f.getAbsolutePath());
158 btn.setBackgroundResource(R.drawable.play);
159 isPlay = true;
160 // 如果在播放中,就改变它的样式
161 adapter.setIndex(current);
162 adapter.notifyDataSetChanged();
163 }
164
165 //暂停
166 public void pause() {
167 //调用服务中的暂停方法
168 ms.PauseMusic();
169 btn.setBackgroundResource(R.drawable.pause);
170 isPlay = false;
171 }
172
173 // 新建广播
174 public class MusicBroadcast extends BroadcastReceiver {
175
176 @Override
177 public void onReceive(Context context, Intent intent) {
178 // 接收广播
179 if (intent.getAction() == "com.firefly.music") {
180 if (intent.getStringExtra("end").equals("播放完毕")) {
181 if ((current + 1) < datas.size()) {
182 //如果播放完毕了,就播放下一首
183 f = new File(datas.get(++current).getUrl());
184 play();
185 } else {
186 Toast.makeText(getApplicationContext(), "已经是最后一首了", 0)
187 .show();
188 }
189 }
190 } else if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
191 //电话监听事件,如果要拨打电话就暂停音乐
192 String rs = getResultData();
193 Toast.makeText(context, "你在拨打" + rs + "的电话了,现在我已经暂停音乐了。", 0).show();
194 pause();
195 } else {
196 //来电也要暂停音乐
197 TelephonyManager telMan = (TelephonyManager) context
198 .getSystemService(Context.TELEPHONY_SERVICE);
199 // 判断电话的状态
200 switch (telMan.getCallState()) {
201 case TelephonyManager.CALL_STATE_RINGING:
202 Log.e("TAG", "响铃");
203 Toast.makeText(getApplicationContext(), "来电话了", 0).show();
204 pause();
205 break;
206
207 case TelephonyManager.CALL_STATE_IDLE:
208 Log.e("TAG", "挂断");
209 Toast.makeText(getApplicationContext(), "您已经挂断,音乐将继续播放", 0).show();
210 play();
211 break;
212
213 case TelephonyManager.CALL_STATE_OFFHOOK:
214 Log.e("TAG", "接听");
215 Toast.makeText(getApplicationContext(), "您正在接收电话,音乐已经暂停", 0).show();
216 pause();
217 break;
218
219 default:
220 break;
221 }
222 }
223 }
224
225 }
226 }
View Code
2-3:写一个接口类,统一管理服务(也可不写)
1 package com.firefly.service;
2
3 public interface IMusic {
4 // 新建一个接口,能用服务来实现它,在这里可以统一管理
5 public void PlayMusic(String music_name);
6
7 public void PauseMusic();
8
9 public void PreviousMusic();
10
11 public void NextMusic();
12 }
IMusic
2-4:服务类
1 package com.firefly.service;
2
3 import android.app.Service;
4 import android.content.Intent;
5 import android.media.AudioManager;
6 import android.media.MediaPlayer;
7 import android.media.MediaPlayer.OnCompletionListener;
8 import android.media.MediaPlayer.OnPreparedListener;
9 import android.os.Binder;
10 import android.os.Handler;
11 import android.os.IBinder;
12 import android.os.Message;
13 import android.util.Log;
14 import android.widget.SeekBar;
15 import android.widget.SeekBar.OnSeekBarChangeListener;
16 import android.widget.Toast;
17
18 public class MusicService extends Service implements IMusic {
19 MediaPlayer music;
20 String music_name;
21 SeekBar sb;
22 Handler handler;
23 boolean flag = false;// 控制线程的播放
24
25 @Override
26 public void PlayMusic(String music_name) {
27 this.music_name = this.music_name;
28 if (music != null && music.isPlaying()) {
29 // 如果在播放的状态下切换到下一首,先把原来的停止、释放、置空,再新建
30 music.stop();
31 music.release();
32 music = null;
33 try {
34 music = new MediaPlayer();
35 music.setAudioStreamType(AudioManager.STREAM_MUSIC);
36 music.setDataSource(music_name);
37 music.prepare();
38 music.start();
39 } catch (Exception e) {
40 // TODO Auto-generated catch block
41 e.printStackTrace();
42 }
43 } else {
44
45 if (music != null) {// 这个状态可能是暂停可能是停止
46 // 如果只是把它暂停,重新开始就可以了
47 music.start();
48 } else {
49 // 第一次播放这首音乐
50 try {
51 music = new MediaPlayer();
52 music.setAudioStreamType(AudioManager.STREAM_MUSIC);
53 music.setDataSource(music_name);
54 music.prepareAsync();
55 // 准备监听事件
56 music.setOnPreparedListener(new OnPreparedListener() {
57 @Override
58 public void onPrepared(MediaPlayer mp) {
59 music.start();
60 // 设置SeekBar
61 int max = music.getDuration();
62 int cur = music.getCurrentPosition();
63 Log.e("TAG", max + "==" + cur);
64 sb.setMax(max);
65 sb.setProgress(cur);
66 sb.setEnabled(true);
67 }
68 });
69 // 音乐播放完毕的监听器
70 music.setOnCompletionListener(new OnCompletionListener() {
71
72 @Override
73 public void onCompletion(MediaPlayer mp) {
74 music.stop();
75 music.release();
76 music = null;
77 // 发送一个广播,已经播放完毕了
78 Intent i = new Intent();
79 i.setAction("com.firefly.music");
80 i.putExtra("end", "播放完毕");
81 sendBroadcast(i);
82
83 }
84 });
85 } catch (Exception e) {
86 e.printStackTrace();
87 }
88 }
89 flag = true;
90 }
91 // 这个线程用来控制进度条的更新
92 Thread th = new Thread(new Runnable() {
93
94 @Override
95 public void run() {
96 while (flag) {
97 try {
98 Thread.sleep(200);
99 } catch (InterruptedException e) {
100 // TODO Auto-generated catch block
101 e.printStackTrace();
102 }
103 Message msg = new Message();
104 msg.what = 0;
105 handler.sendMessage(msg);
106 }
107 }
108 });
109 th.start();
110
111 }
112
113 @Override
114 public void PauseMusic() {
115 // TODO Auto-generated method stub
116 if (music != null && music.isPlaying()) {
117 music.pause();
118 flag = false;
119 }
120 }
121
122 @Override
123 public void PreviousMusic() {
124 // TODO Auto-generated method stub
125
126 }
127
128 @Override
129 public void NextMusic() {
130 // TODO Auto-generated method stub
131
132 }
133
134 public void setSeekBar(final SeekBar sb) {
135 this.sb = sb;
136 sb.setEnabled(false);// 没开始播放的时候进度条是不能拖动的
137 sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
138
139 @Override
140 public void onStopTrackingTouch(SeekBar seekBar) {
141 // TODO Auto-generated method stub
142 if (music != null) {
143 music.seekTo(seekBar.getProgress());
144 }
145 }
146
147 @Override
148 public void onStartTrackingTouch(SeekBar seekBar) {
149 // TODO Auto-generated method stub
150
151 }
152
153 @Override
154 public void onProgressChanged(SeekBar seekBar, int progress,
155 boolean fromUser) {
156 // TODO Auto-generated method stub
157
158 }
159 });
160
161 handler = new Handler() {
162 @Override
163 public void handleMessage(Message msg) {
164 switch (msg.what) {
165 case 0:
166 if (music != null) {
167 // 播放和SeekBar同步
168 sb.setProgress(music.getCurrentPosition());
169 }
170 break;
171
172 default:
173 break;
174 }
175 }
176
177 };
178
179 }
180
181 @Override
182 public IBinder onBind(Intent intent) {
183 // TODO Auto-generated method stub
184 return new MyBinder();
185 }
186
187 public class MyBinder extends Binder {
188 public MusicService getService() {
189 return MusicService.this;
190 }
191 }
192
193 }
MusicService
3、清单文件
1 <?xml version="1.0" encoding="utf-8"?>
2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.firefly.beautifulmusic"
4 android:versionCode="1"
5 android:versionName="1.0" >
6
7 <uses-sdk
8 android:minSdkVersion="14"
9 android:targetSdkVersion="19" />
10 <!-- 读写SD卡的权限、读取电话状态的权限 -->
11 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
12 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
13 <uses-permission android:name="android.permission.READ_PHONE_STATE" />
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=".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
30 <service android:name="com.firefly.service.MusicService" >
31 </service>
32 </application>
33
34 </manifest>
Manifest
4、效果图