目录
MediaPlayer 简 介
音频操作
播放 raw 中的文件
视频操作
播放 raw 中的文件
Android 多媒体中的——MediaPlayer 可以用来播放音频和视频,是 Androd 多媒体框架中的一个重要组件,通过该类,可以以最小的步骤来获取,解码 和播放音视频。
MediaPlayer 支持三种不同的媒体来源:
1) 本地资源
2) 内部的 URI,比如可以通过 ContentResolver 来获取
3) 外部的 URL(流) 对于Android所支持的的媒体格式列表,可见:Supported Media Formats 文档
官方 API 文档:MediaPlayer
1)获得 MediaPlayer 实例,可以直接 new 或者调用create方法创建,如下只是常用的两种,还有其它重载的方法:
MediaPlayer mp = new MediaPlayer(); // 之后 调用 setDataSource 设置播放的资源
MediaPlayer mp = MediaPlayer.create(this, R.raw.test); //无需再调用 setDataSource 设置播放的资源
2)设置播放文件:
//①raw下的资源:
MediaPlayer.create(this, R.raw.test);//②本地文件路径:
mp.setDataSource("/sdcard/test.mp3");//③网络URL文件:
mp.setDataSource("http://www.xxx.com/music/test.mp3");
另外 setDataSource() 方法有多个,里面有这样一个类型的参数:FileDescriptor,在使用这个 API的时候,需要把文件放到res文件夹平级的assets文件夹里,然后使用下述代码设置DataSource:
AssetFileDescriptor fileDescriptor = getAssets().openFd("rain.mp3");
m_mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(), fileDescriptor.getLength());
3)常用 API 描述
getCurrentPosition( ):得到当前的播放位置
getDuration() :得到文件的时间
getVideoHeight() :得到视频高度
getVideoWidth() :得到视频宽度
isLooping():是否循环播放
isPlaying():是否正在播放
pause():暂停
prepare():准备(同步)
prepareAsync():准备(异步)
release():释放MediaPlayer对象
reset():重置MediaPlayer对象
seekTo(int msec):指定播放的位置(以毫秒为单位的时间)
setAudioStreamType(int streamtype):指定流媒体的类型
setDisplay(SurfaceHolder sh):设置用SurfaceHolder来显示多媒体
setLooping(boolean looping):设置是否循环播放
setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener): 网络流媒体的缓冲监听
setOnCompletionListener(MediaPlayer.OnCompletionListener listener): 网络流媒体播放结束监听
setOnErrorListener(MediaPlayer.OnErrorListener listener): 设置错误信息监听
setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener): 视频尺寸监听
setScreenOnWhilePlaying(boolean screenOn):设置是否使用SurfaceHolder显示
setVolume(float leftVolume, float rightVolume):设置音量
start():开始播放
stop():停止播放
现在来用 MediaPlayer 来写个简单的播放 res/raw 目录中的音频例子,效果如下:点击 “播放” 按钮,音乐开始播放;点击 “暂停” 按钮,音乐暂停播放,再次点击“播放”时继续;点击“退出”按钮,音乐退回初始位置,等待播放。
activity_main.xml 布局文件内容如下:
MainActivity.java 文件内容如下:
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import java.io.IOException;
import static android.icu.lang.UCharacter.GraphemeClusterBreak.L;
/**
* 一个应用程序可以有1个或多个活动,而没有任何限制。
* 每个为应用程序所定义的活动都需要在 AndroidManifest.xml 中声明,应用的主活动的意图过滤器标签中需要包含 MAIN 动作和 LAUNCHER 类别
* 如果 MAIN 动作还是 LAUNCHER 类别没有在活动中声明,那么应用程序的图标将不会出现在主屏幕的应用列表中。
* implements View.OnClickListener:用于绑定单击事件
*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
/**
* TAG:Log.d(String tag, String msg) 的消息标签
* btn_play:播放按钮
* btn_stop:暂停按钮
* btn_quit:退出重置按钮
* isRelease:判断 MediaPlayer 是否释放的标志
*/
private static final String TAG = "MainActivity : ";
private Button btn_play;
private Button btn_stop;
private Button btn_quit;
private MediaPlayer mPlayer = null;
private boolean isRelease = true;
/**
* 当活动第一次被创建时调用
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/**
* 从项目的 res/layout 中的XML文件加载 UI 组件
* android.util.Log#d(java.lang.String, java.lang.String) 方法用于在 Logcat 窗口中打印日志
*/
setContentView(R.layout.activity_main);
Log.d(TAG, "The onCreate(Bundle savedInstanceState) .....");
bindViews();
}
/**
* 为按钮 绑定单击事件
*/
private void bindViews() {
btn_play = findViewById(R.id.btnStart);
btn_stop = findViewById(R.id.btnStop);
btn_quit = findViewById(R.id.btnQuit);
/**初始条件下只有 播放 按钮能点击,暂停、退出按钮不能点击*/
btn_stop.setEnabled(false);
btn_quit.setEnabled(false);
btn_play.setOnClickListener(this);
btn_stop.setOnClickListener(this);
btn_quit.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Log.d(TAG, "-----------" + v.getId());
switch (v.getId()) {
case R.id.btnStart:
/**如果当前 MediaPlayer 未关联播放的文件,则进行关联
* 播放的是 res/raw 目录下的 day_by_day.mp3 文件
*/
if (isRelease) {
mPlayer = MediaPlayer.create(this, R.raw.day_by_day);
isRelease = false; //设置标识
}
mPlayer.start(); //开始播放
btn_play.setEnabled(false); //禁用播放按钮
btn_stop.setEnabled(true); //启用暂停按钮
btn_quit.setEnabled(true); //启用退出按钮
int currentPosition = mPlayer.getCurrentPosition(); // 获取当前播放的位置,单位毫秒
int duration = mPlayer.getDuration();//获取文件的总时间长度,成功时以毫秒返回,否则为 -1,如直播流
boolean isLooping = mPlayer.isLooping();//是否正在循环播放
Log.d(TAG, "文件总时间:" + duration + " 毫秒");
Log.d(TAG, "文件当前播放时间:" + currentPosition + " 毫秒");
Log.d(TAG, "文件是否循环播放:" + isLooping);
break;
case R.id.btnStop:
mPlayer.pause(); //停止播放
btn_play.setEnabled(true); //启用播放按钮
btn_stop.setEnabled(false); //禁用暂停按钮
btn_quit.setEnabled(false); //禁用退出按钮
break;
case R.id.btnQuit:
mPlayer.reset(); //重置MediaPlayer
mPlayer.release(); //释放MediaPlayer,即释放与此媒体播放器对象关联的资源。
isRelease = true; //设置标识
btn_play.setEnabled(true); //启用播放按钮
btn_stop.setEnabled(false); //禁用暂停按钮
btn_quit.setEnabled(false); //禁用退出按钮
break;
}
}
}
以 “播放”—>“暂停”->"播放"->"暂停"->"播放"—>"退出"->"播放"的顺序点击后,控制台输出如下:
D/MainActivity :: -----------2131165220
D/MainActivity :: 文件总时间:60757 毫秒
文件当前播放时间:0 毫秒
文件是否循环播放:false
D/MainActivity :: -----------2131165221
D/MainActivity :: -----------2131165220
D/MainActivity :: 文件总时间:60757 毫秒
D/MainActivity :: 文件当前播放时间:6332 毫秒
文件是否循环播放:false
D/MainActivity :: -----------2131165221
D/MainActivity :: -----------2131165220
D/MainActivity :: 文件总时间:60757 毫秒
文件当前播放时间:13001 毫秒
文件是否循环播放:false
D/MainActivity :: -----------2131165219
D/MainActivity :: -----------2131165220
E/MediaPlayer: Should have subtitle controller already set
D/MainActivity :: 文件总时间:60757 毫秒
文件当前播放时间:0 毫秒
文件是否循环播放:false
MediaPlayer 主要用于播放音频,没有提供图像输出界面,所以需要借助其他的组件来显示 MediaPlayer 播放的图像,可以使用 SurfaceView 来显示。
下面以播放 res/raw 目录下的视频文件为例进行说明,效果图如下:
布局文件 activity_main.xml 代码如下:
MainActivity.java 文件内容如下:
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import java.io.IOException;
import static android.icu.lang.UCharacter.GraphemeClusterBreak.L;
import static android.icu.lang.UCharacter.GraphemeClusterBreak.T;
/**
* 一个应用程序可以有1个或多个活动,而没有任何限制。
* 每个为应用程序所定义的活动都需要在 AndroidManifest.xml 中声明,应用的主活动的意图过滤器标签中需要包含 MAIN 动作和 LAUNCHER 类别
* 如果 MAIN 动作还是 LAUNCHER 类别没有在活动中声明,那么应用程序的图标将不会出现在主屏幕的应用列表中。
* implements View.OnClickListener:用于绑定单击事件
* implements SurfaceHolder.Callback:用于监测 surface 的状态,重写其三个方法
* android.view.SurfaceHolder 是接口,Callback 是 SurfaceHolder 的子接口
*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener, SurfaceHolder.Callback {
/**
* TAG:Log.d(String tag, String msg) 的消息标签
*
* btn_play:播放按钮
* btn_stop:暂停按钮
* btn_quit:重新开始按钮
* android.media.MediaPlayer:媒体播放器
* android.view.SurfaceView:表面/外观视图
* android.view.SurfaceHolder:表面/外观视图所有者
*/
private static final String TAG = "MainActivity : ";
private Button btn_play;
private Button btn_stop;
private Button btn_restart;
private MediaPlayer mediaPlayer = null;
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
/**
* 当活动第一次被创建时调用
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/**
* 从项目的 res/layout 中的XML文件加载 UI 组件
* android.util.Log#d(java.lang.String, java.lang.String) 方法用于在 Logcat 窗口中打印日志
*/
setContentView(R.layout.activity_main);
Log.d(TAG, "The onCreate(Bundle savedInstanceState) .....");
bindViews();
}
/**
* 为按钮 绑定单击事件
* 初始化 SurfaceHolder 类,SurfaceView 的控制器
*/
private void bindViews() {
surfaceView = findViewById(R.id.sfv_show);
btn_play = findViewById(R.id.btnStart);
btn_stop = findViewById(R.id.btnStop);
btn_restart = findViewById(R.id.btnRestart);
/**通过android.view.SurfaceView 获得 android.view.SurfaceHolder 实例*/
surfaceHolder = surfaceView.getHolder();
/**添加回调*/
surfaceHolder.addCallback(this);
/**设置表面视图显示的分辨率,不设置为视频默认*/
surfaceHolder.setFixedSize(320, 220);
}
@Override
public void onClick(View v) {
Log.d(TAG, "onClick-----------" + v.getId());
switch (v.getId()) {
case R.id.btnStart:// 播放按钮
mediaPlayer.start();//开始播放
btn_play.setEnabled(false);//禁用播放按钮
btn_stop.setEnabled(true);//启用暂停按钮
btn_restart.setEnabled(true);//启用重新播放按钮
break;
case R.id.btnStop:
mediaPlayer.pause();//暂停播放
btn_play.setEnabled(true);//启用播放按钮
btn_stop.setEnabled(false);//禁用暂停按钮
btn_restart.setEnabled(true);//启用重新播放按钮
break;
case R.id.btnRestart:
btn_play.setEnabled(false);//禁用播放按钮
btn_stop.setEnabled(true);//启用暂停按钮
btn_restart.setEnabled(false);//禁用重新播放按钮
mediaPlayer.reset();//重置 MediaPlayer 对象
mediaPlayer.release();// 释放MediaPlayer资源
/**
* 然后重新进行绑定资源、
* 指定流媒体类型、
* 设置用SurfaceHolder来显示多媒体、
* 再重新播放
*/
mediaPlayer = MediaPlayer.create(MainActivity.this, R.raw.la_isla);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDisplay(surfaceHolder);
mediaPlayer.start();
break;
}
}
/**
* 重写的 android.view.SurfaceHolder.Callback 接口中的方法
* surfaceView 视图每次创建时都会自动执行此方法
* 只要视频播放界面重新回到第一层,即用户能直接操作时,就会自动执行此方法
*
* @param holder
*/
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated......................");
/**播放前,设置播放按钮激活、暂停按钮禁用、重新开始按钮禁用*/
btn_play.setOnClickListener(this);
btn_stop.setOnClickListener(this);
btn_restart.setOnClickListener(this);
/**界面初始化时媒体播放器,然后设置流媒体类型,最后用 SurfaceHolder显示出来*/
mediaPlayer = MediaPlayer.create(MainActivity.this, R.raw.la_isla);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDisplay(surfaceHolder); //设置显示视频显示在SurfaceView上
}
/**
* 重写的 android.view.SurfaceHolder.Callback 接口中的方法
* 只要 Surface 视图有变化,此方法就会自动执行
*
* @param holder
* @param format
* @param width
* @param height
*/
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "surfaceChanged.................");
}
/**
* 重写的 android.view.SurfaceHolder.Callback 接口中的方法
* 当界面被其它界面覆盖时,或者直接被退出时,就会自动执行此方法
* 被覆盖时,则停止播放,然后释放资源
* 注意:如果界面被覆盖了没有 stop停止播放,或者释放资源,就会出现视频在后台有声音出来
* 当再次进入界面时,只有声音,没有画面
*
* @param holder
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "surfaceDestroyed.................");
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
}