本文介绍MediaPlayer的使用。MediaPlayer可以播放音频和视频,另外也可以通过VideoView来播放视频,虽然VideoView比MediaPlayer简单易用,但定制性不如用MediaPlayer,要视情况选择了。MediaPlayer播放音频比较简单,但是要播放视频就需要SurfaceView。SurfaceView比普通的自定义View更有绘图上的优势,它支持完全的OpenGL ES库。
先贴出本文程序运行结果的截图,下面是上一首、下一首、播放、停止、自动下一首、可用SeekBar来调进度:
布局文件:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout 3 xmlns:android="http://schemas.android.com/apk/res/android"
4 xmlns:app="http://schemas.android.com/apk/res-auto"
5 xmlns:tools="http://schemas.android.com/tools"
6 android:layout_width="match_parent"
7 android:layout_height="match_parent"
8 android:orientation="vertical"
9 tools:context="net.bwie.mediaplayer.MainActivity">
10
11 <RelativeLayout 12 android:layout_width="match_parent"
13 android:layout_height="wrap_content">
14
15 <TextView 16 android:id="@+id/current_time_tv"
17 android:layout_width="wrap_content"
18 android:layout_height="wrap_content"
19 android:text="当前时间"/>
20
21 <TextView 22 android:id="@+id/total_time_tv"
23 android:layout_width="wrap_content"
24 android:layout_height="wrap_content"
25 android:layout_alignParentRight="true"
26 android:text="全部时间"/>
27
28 <SeekBar 29 android:id="@+id/seek_bar"
30 style="?android:progressBarStyleHorizontal"
31 android:layout_width="match_parent"
32 android:layout_height="50dp"
33 android:layout_toLeftOf="@id/total_time_tv"
34 android:layout_toRightOf="@id/current_time_tv"/>
35
36 </RelativeLayout>
37
38 <LinearLayout 39 android:layout_width="match_parent"
40 android:layout_height="wrap_content">
41
42 <Button 43 android:id="@+id/previous_btn"
44 android:layout_width="0dp"
45 android:layout_height="wrap_content"
46 android:layout_weight="1"
47 android:text="上一曲"/>
48
49 <Button 50 android:id="@+id/play_btn"
51 android:layout_width="0dp"
52 android:layout_height="wrap_content"
53 android:layout_weight="1"
54 android:text="播放/暂停"/>
55
56 <Button 57 android:id="@+id/next_btn"
58 android:layout_width="0dp"
59 android:layout_height="wrap_content"
60 android:layout_weight="1"
61 android:text="下一曲"/>
62
63 </LinearLayout>
64
65
66 <ListView 67 android:id="@+id/list_view"
68 android:layout_width="match_parent"
69 android:layout_height="match_parent"
70 android:divider="#f00"
71 android:dividerHeight="2dp"/>
72
73 </LinearLayout>
Bean类:
1 package net.bwie.mediaplayer.bean; 2
3 public class MediaInfo { 4
5 private long _id; 6 private String uri;// 路径
7 private String title; 8 private String artist;// 艺术家
9
10 public MediaInfo(long _id, String uri, String title, String artist) { 11 this._id = _id; 12 this.uri = uri; 13 this.title = title; 14 this.artist = artist; 15 } 16
17 public long get_id() { 18 return _id; 19 } 20
21 public void set_id(long _id) { 22 this._id = _id; 23 } 24
25 public String getUri() { 26 return uri; 27 } 28
29 public void setUri(String uri) { 30 this.uri = uri; 31 } 32
33 public String getTitle() { 34 return title; 35 } 36
37 public void setTitle(String title) { 38 this.title = title; 39 } 40
41 public String getArtist() { 42 return artist; 43 } 44
45 public void setArtist(String artist) { 46 this.artist = artist; 47 } 48
49 @Override 50 public String toString() { 51 return "MediaInfo{" +
52 "_id=" + _id +
53 ", uri='" + uri + '\'' +
54 ", title='" + title + '\'' +
55 ", artist='" + artist + '\'' +
56 '}'; 57 } 58 }
Activity主页面:
1 /**
2 * 1、查询全部歌曲信息并展示(ContentProvider数据库) 3 * 2、点击对应歌曲播放/暂停 4 * 3、播放/暂停按钮。上一首/下一首 5 * 注意:设置外部存储权限 6 * build.gradle中targetSdkVersion 22 7 * <p> 8 * 进度条部分 9 * 1、进度条跟随歌曲进度而变化 10 * 实现周期性改变进度条位置:1、Handler,2、TimerTask定时器 11 * 2、拖动进度条让MediaPlayer播放对应位置的声音 12 * SeekBar绑定监听器 13 * MediaPlayer绑定播放完毕监听器,实现自动播放下一曲 14 */
15 public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener, View.OnClickListener, SeekBar.OnSeekBarChangeListener, MediaPlayer.OnCompletionListener { 16
17 protected ListView mListView; 18 protected Button mPreviousBtn; 19 protected Button mPlayBtn; 20 protected Button mNextBtn; 21 protected TextView mCurrentTimeTv; 22 protected TextView mTotalTimeTv; 23 protected SeekBar mSeekBar; 24 private List<MediaInfo> mMediaInfoList; 25
26 private MediaPlayer mMediaPlayer; 27
28 // 记录当前播放歌曲的位置
29 private int mCurrentPosition; 30
31 private Handler mHandler = new Handler(new Handler.Callback() { 32 @Override 33 public boolean handleMessage(Message msg) { 34
35 // 展示给进度条和当前时间
36 int progress = mMediaPlayer.getCurrentPosition(); 37 mSeekBar.setProgress(progress); 38 mCurrentTimeTv.setText(parseTime(progress)); 39
40 // 继续定时发送数据
41 updateProgress(); 42
43 return true; 44 } 45 }); 46
47 @Override 48 protected void onCreate(Bundle savedInstanceState) { 49 super.onCreate(savedInstanceState); 50 super.setContentView(R.layout.activity_main); 51 initView(); 52
53 mMediaInfoList = getDatas(); 54
55 ArrayAdapter adapter = new ArrayAdapter(this, 56 android.R.layout.simple_list_item_1, 57 mMediaInfoList); 58
59 mListView.setAdapter(adapter); 60 mListView.setOnItemClickListener(this); 61 } 62
63 private void initView() { 64 mListView = (ListView) findViewById(R.id.list_view); 65 mPreviousBtn = (Button) findViewById(R.id.previous_btn); 66 mPreviousBtn.setOnClickListener(MainActivity.this); 67 mPlayBtn = (Button) findViewById(R.id.play_btn); 68 mPlayBtn.setOnClickListener(MainActivity.this); 69 mNextBtn = (Button) findViewById(R.id.next_btn); 70 mNextBtn.setOnClickListener(MainActivity.this); 71 mCurrentTimeTv = (TextView) findViewById(R.id.current_time_tv); 72 mTotalTimeTv = (TextView) findViewById(R.id.total_time_tv); 73 mSeekBar = (SeekBar) findViewById(R.id.seek_bar); 74
75 // SeekBar绑定监听器,监听拖动到指定位置
76 mSeekBar.setOnSeekBarChangeListener(this); 77
78 } 79
80 // 获取系统媒体数据库中的音频多媒体信息
81 private List<MediaInfo> getDatas() { 82 List<MediaInfo> list = new ArrayList<>(); 83
84 // 使用内容解析者访问系统提供的数据库
85 Cursor cursor = getContentResolver() 86 .query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 87 null, 88 null, 89 null, 90 MediaStore.Audio.Media.DEFAULT_SORT_ORDER);// 默认排序顺序 91 // 如果游标读取时还有下一个数据,读取
92
93 int idIndex = cursor.getColumnIndex(MediaStore.Audio.Media._ID);//获取列名对应的索引
94 int titleIndex = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);// 标题
95 int artistIndex = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);// 艺术家
96 int uriIndex = cursor.getColumnIndex(MediaStore.Audio.Media.DATA);// 文件路径
97 while (cursor.moveToNext()) { 98 // 根据索引值获取对应列名中的数值
99 long _id = cursor.getLong(idIndex); 100 String title = cursor.getString(titleIndex); 101 String artist = cursor.getString(artistIndex); 102 String uri = cursor.getString(uriIndex); 103
104 MediaInfo mediaInfo = new MediaInfo(_id, uri, title, artist); 105
106 list.add(mediaInfo); 107 } 108
109 for (MediaInfo mediaInfo : list) { 110 Log.d("1507", "" + mediaInfo.toString()); 111 } 112 return list; 113 } 114
115 @Override 116 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 117 mCurrentPosition = position; 118
119 changeMusic(mCurrentPosition); 120 } 121
122 @Override 123 public void onClick(View view) { 124
125 if (view.getId() == R.id.previous_btn) {// 上一首
126 changeMusic(--mCurrentPosition); 127 } else if (view.getId() == R.id.play_btn) {// 播放/暂停 128
129 // 首次点击播放按钮,默认播放第0首
130 if (mMediaPlayer == null) { 131 changeMusic(0); 132 } else { 133 playOrPause(); 134 } 135
136 } else if (view.getId() == R.id.next_btn) {// 下一首
137 changeMusic(++mCurrentPosition); 138 } 139
140 } 141
142 // 播放或暂停
143 private void playOrPause() { 144 if (mMediaPlayer.isPlaying()) { 145 mMediaPlayer.pause(); 146 } else { 147 mMediaPlayer.start(); 148 } 149 } 150
151 // 基本数据类型和String在方法调用中传递的是值 152 // 其他数据类型在方法调用中传递的是引用 153
154 // 切歌
155 private void changeMusic(int position) { 156 if (position < 0) { 157 mCurrentPosition = position = mMediaInfoList.size() - 1; 158 } else if (position > mMediaInfoList.size() - 1) { 159 mCurrentPosition = position = 0; 160 } 161
162 if (mMediaPlayer == null) { 163 mMediaPlayer = new MediaPlayer(); 164 // 绑定播放完毕监听器
165 mMediaPlayer.setOnCompletionListener(this); 166 } 167
168 try { 169 // 切歌之前先重置,释放掉之前的资源
170 mMediaPlayer.reset(); 171 // 设置播放源
172 mMediaPlayer.setDataSource(mMediaInfoList.get(position).getUri()); 173 // 开始播放前的准备工作,加载多媒体资源,获取相关信息
174 mMediaPlayer.prepare(); 175 // 开始播放
176 mMediaPlayer.start(); 177 } catch (IOException e) { 178 e.printStackTrace(); 179 Toast.makeText(this, "播放错误", Toast.LENGTH_SHORT).show(); 180 } 181
182 // 切歌时重置进度条并展示歌曲时长
183 mSeekBar.setProgress(0); 184 mSeekBar.setMax(mMediaPlayer.getDuration()); 185 mTotalTimeTv.setText(parseTime(mMediaPlayer.getDuration())); 186
187 updateProgress(); 188 } 189
190 // 每间隔1s通知更新进度
191 private void updateProgress() { 192 // 使用Handler每间隔1s发送一次空消息,通知进度条更新
193 Message msg = Message.obtain();// 获取一个现成的消息
194 mHandler.sendMessageDelayed(msg, INTERNAL_TIME); 195 } 196
197 // 解析时间
198 private String parseTime(int oldTime) { 199 SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");// 时间格式
200 String newTime = sdf.format(new Date(oldTime)); 201 return newTime; 202 } 203
204 private static final int INTERNAL_TIME = 1000;// 音乐进度间隔时间
205
206 @Override 207 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 208
209 } 210
211 @Override 212 public void onStartTrackingTouch(SeekBar seekBar) { 213
214 } 215
216 // 当手停止拖拽进度条时执行该方法 217 // 获取拖拽进度 218 // 将进度对应设置给MediaPlayer
219 @Override 220 public void onStopTrackingTouch(SeekBar seekBar) { 221 int progress = seekBar.getProgress(); 222 mMediaPlayer.seekTo(progress); 223 } 224
225 @Override 226 public void onCompletion(MediaPlayer mp) { 227 // 当歌曲播放完毕,切歌到下一首
228 changeMusic(++mCurrentPosition); 229 } 230 }
权限:
1 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>