Android 多媒體MediaPlayer使用詳解
現在的手機功能越來越豐富了,遙想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() |
獲取載入的視訊檔案的時長。 |
比如:
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的生命週期(上圖)進行錯誤分析。好了,先寫到這,對以上內容有疑惑或紕漏的地方,歡迎留言指出!