現在的手機功能越來越豐富了,遙想10年前,MP3,MP4,MP5,還是很流行的,博主當時讀高中時很想擁有一台,可以聽音樂和看電影。可是條件有限,學校也禁止此東西,所以只能偷偷的玩。而現在我們的手機也很早以前就支持了這些功能,而且界面和功能也遠遠超過了MP4。好吧,說多了,今天本文介紹的是Andriod系統自帶的Mediaplayer,和VideoView實現簡單的音樂和視頻的播放,至於想做出如酷狗音樂這樣的APP的話,只要想做,應該也不難,都是基於此實現了功能的擴展。
Android的MediaPlayer包含了Audio和Video的播放功能,在Android的界面上,Music和Video兩個應用程序都是調用MediaPlaer來實現的。
一、播放音頻文件
首先看看MediaPlaer的生命周期
下面是MediaPlayer提供的常用方法
方法 | 說明 |
MediaPlayer | 構造方法 |
create | 創建一個要播放的多媒體 |
getCurrentPosition | 得到當前播放位置 |
getDuration | 得到文件的時間 |
getVideoHeight | 得到視頻的高度 |
getVideoWidth | 得到視頻的寬度 |
isLooping | 是否循環播放 |
isPlaying | 是否正在播放 |
pause | 暫停 |
prepare | 准備(同步) |
prepareAsync | 准備(異步) |
release | 釋放MediaPlayer對象相關的資源 |
reset | 重置MediaPlayer對象為剛剛創建的狀態 |
seekTo | 指定播放的位置(以毫秒為單位的時間) |
setAudioStreamType | 設置流媒體的類型 |
setDataSource | 設置多媒體數據來源(位置) |
setDisplay | 設置用SurfaceHolder來顯示多媒體 |
setLooping | 設置是否循環播放 |
setOnButteringUpdateListener | 網絡流媒體的緩沖監聽 |
setOnErrorListener | 設置錯誤信息監聽 |
setOnVideoSizeChangedListener | 視頻尺寸監聽 |
setScreenOnWhilePlaying | 設置是否使用SurfaceHolder來保持屏幕顯示 |
setVolume | 設置音量 |
start | 開始播放 |
stop | 停止播放 |
MediaPlayer的工作流程是這樣的:
1,首先創建MediaPlaer對象; *
2,然后調用setDataSource()方法來設置音頻文件的路徑;**
3,再調用prepare()方法使MediaPlayer進入到准備狀態;
4,調用start方法就可以播放音頻。
* 創建MediaPlaer對象有兩種方式
a 直接new出來
- MediaPlayer mp = new MediaPlayer();
b 使用create方式
- MediaPlayer mp = MediaPlayer.create(this, R.raw.test);//這時就不用調用setDataSource了
當然上面首先得在res文件夾下新建raw文件夾,並放置一個test文件
** 設置播放的文件
MediaPlayer要播放的文件主要包括3個來源:
a. 用戶在應用中事先自帶的resource資源
例如:MediaPlayer.create(this, R.raw.test);
b. 存儲在SD卡或其他文件路徑下的媒體文件
例如:mp.setDataSource("/sdcard/test.mp3");
c. 網絡上的媒體文件
例如:mp.setDataSource("http://www.citynorth.cn/music/confucius.mp3");
MediaPlayer的setDataSource一共四個方法:
setDataSource (String path)
setDataSource (FileDescriptor fd)
setDataSource (Context context, Uri uri)
setDataSource (FileDescriptor fd, long offset, long length)
其中使用FileDescriptor時,需要將文件放到與res文件夾平級的assets文件夾里,然后使用:
AssetFileDescriptor fileDescriptor = getAssets().openFd("rain.mp3");
m_mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(), fileDescriptor.getLength());
來設置datasource
先簡單看下效果圖吧
上面的功能一看就知道了,就不用我說了吧
下面是實現代碼
activity_main.xml
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_margin="3dp"
- android:orientation="vertical" >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <Button
- android:id="@+id/play"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="播放" />
- <Button
- android:id="@+id/pause"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="暫停" />
- <Button
- android:id="@+id/stop"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="停止" />
- </LinearLayout>
- <SeekBar
- android:id="@+id/seekbar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:max="0"
- android:progress="0"
- android:secondaryProgress="0" />
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content" >
- <TextView
- android:id="@+id/tv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:text="當前時間" />
- <TextView
- android:id="@+id/tv2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:text="總時間" />
- </RelativeLayout>
- </LinearLayout>
MainActivity.java
- package com.example.musicplayer;
- import java.io.File;
- import java.io.IOException;
- import android.R.integer;
- import android.app.Activity;
- import android.media.MediaPlayer;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.Handler;
- import android.os.Message;
- import android.util.Log;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.SeekBar;
- import android.widget.SeekBar.OnSeekBarChangeListener;
- import android.widget.TextView;
- public class MainActivity extends Activity implements OnClickListener,
- OnSeekBarChangeListener {
- private Button play, pause, stop;
- private MediaPlayer player;
- private SeekBar mSeekBar;
- private TextView tv, tv2;
- private boolean hadDestroy = false;
- private Handler mHandler = new Handler() {
- public void handleMessage(android.os.Message msg) {
- switch (msg.what) {
- case 0x01:
- break;
- default:
- break;
- }
- };
- };
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- if (!hadDestroy) {
- mHandler.postDelayed(this, 1000);
- int currentTime = Math
- .round(player.getCurrentPosition() / 1000);
- String currentStr = String.format("%s%02d:%02d", "當前時間 ",
- currentTime / 60, currentTime % 60);
- tv.setText(currentStr);
- mSeekBar.setProgress(player.getCurrentPosition());
- }
- }
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- play = (Button) findViewById(R.id.play);
- pause = (Button) findViewById(R.id.pause);
- stop = (Button) findViewById(R.id.stop);
- mSeekBar = (SeekBar) findViewById(R.id.seekbar);
- tv = (TextView) findViewById(R.id.tv);
- tv2 = (TextView) findViewById(R.id.tv2);
- mSeekBar.setOnSeekBarChangeListener(this);
- play.setOnClickListener(this);
- pause.setOnClickListener(this);
- stop.setOnClickListener(this);
- player = new MediaPlayer();
- initMediaplayer();
- }
- /**
- * 初始化播放器
- */
- private void initMediaplayer() {
- try {
- File file = new File(Environment.getExternalStorageDirectory()
- + "/Download/", "aiqiu.mp3");
- player.setDataSource(file.getPath());
- Log.e("播放器", file.toString());
- player.prepare();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.play:
- if (!player.isPlaying()) {
- player.start();
- int totalTime = Math.round(player.getDuration() / 1000);
- String str = String.format("%02d:%02d", totalTime / 60,
- totalTime % 60);
- tv2.setText(str);
- mSeekBar.setMax(player.getDuration());
- mHandler.postDelayed(runnable, 1000);
- }
- break;
- case R.id.pause:
- if (player.isPlaying()) {
- player.pause();
- }
- break;
- case R.id.stop:
- if (player.isPlaying()) {
- player.reset();
- initMediaplayer();
- }
- break;
- default:
- break;
- }
- }
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress,
- boolean fromUser) {
- if (player != null) {
- player.seekTo(seekBar.getProgress());
- }
- }
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- // TODO 自動生成的方法存根
- }
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- // TODO 自動生成的方法存根
- }
- @Override
- protected void onDestroy() {
- // TODO 自動生成的方法存根
- super.onDestroy();
- if (player != null) {
- player.stop();
- hadDestroy = true;
- player.release();
- }
- }
- }
二、播放視頻文件
播放視頻文件相比播放音頻文件並不比它復雜,這里使用VideoView類來實現。這個類將視頻的顯示和控制集於一身。
VideoView和MediaPlaer也比較類似,主要有以下常用方法
方法名 |
功能描述 |
setVideoPath() |
設置要播放的視頻文件的位置。 |
start() |
開始或繼續播放視頻。 |
pause() |
暫停播放視頻。 |
resume() |
將視頻重頭開始播放。 |
seekTo() |
從指定的位置開始播放視頻。 |
isPlaying() |
判斷當前是否正在播放視頻。 |
getDuration() |
獲取載入的視頻文件的時長。 |
因為VideoView是包裝過的MediaPlayer,所以使用起來很相似。
比如:
- private void initVideoPlayer() {
- File file = new File(Environment.getExternalStorageDirectory()
- + "/Download/", "Sample.3gp");
- videoPlayer.setVideoPath(file.getPath());// 指定視頻文件的路徑
- }
事件處理
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.play:
- if (!videoPlayer.isPlaying()) {
- videoPlayer.start();
- }
- break;
- case R.id.pause:
- if (videoPlayer.isPlaying()) {
- videoPlayer.pause();
- }
- break;
- case R.id.stop:
- if (videoPlayer.isPlaying()) {
- videoPlayer.resume();
- }
- break;
- default:
- break;
- }
- }
三、常見的MediaPlayer錯誤
也就是它的錯誤狀態。比如這樣的錯誤 start called in state 0,0表示他的錯誤狀態,下面是MediaPlayer的狀態,源碼中找到的:
- enum media_player_states {
- MEDIA_PLAYER_STATE_ERROR = 0, // 0狀態
- MEDIA_PLAYER_IDLE = 1 << 0, // 1狀態
- MEDIA_PLAYER_INITIALIZED = 1 << 1, // 2 狀態
- MEDIA_PLAYER_PREPARING = 1 << 2, // 4 狀態
- MEDIA_PLAYER_PREPARED = 1 << 3, // 8狀態
- MEDIA_PLAYER_STARTED = 1 << 4, // 16狀態
- MEDIA_PLAYER_PAUSED = 1 << 5, // 32狀態
- MEDIA_PLAYER_STOPPED = 1 << 6, // 64 狀態
- MEDIA_PLAYER_PLAYBACK_COMPLETE = 1 << 7, // 128 狀態
- }
可以參照報錯的狀態和MediaPlayer的生命周期(上圖)進行錯誤分析。