Android三種播放視頻的方式(以下內(nèi)容大多使用真機測試侄泽,所以沒有運行圖片顿天,大家可以自己實戰(zhàn)看看)
1、使用其自帶的播放器腺兴。指定Action為ACTION_VIEW,Data為Uri左电,Type為其MIME類型。
2页响、使用VideoView來播放篓足。在布局文件中使用VideoView結合MediaController來實現(xiàn)對其控制。
3闰蚕、使用MediaPlayer類和SurfaceView來實現(xiàn)栈拖,這種方式很靈活。
使用前先添加權限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
1陪腌、調(diào)用其自帶的播放器:
Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath()+"/Movie.mp4");
//調(diào)用系統(tǒng)自帶的播放器
Intent intent = new Intent(Intent.ACTION_VIEW);
Log.v("URI:::::::::", uri.toString());
intent.setDataAndType(uri, "video/mp4");
startActivity(intent);
2辱魁、使用VideoView來播放)
使VideoView主要有以下方法:
方法名 | 作用 |
---|---|
setVideoPath() | 設置要播放的視頻的文件路徑 |
start() | 開始或繼續(xù)播放 |
pause() | 暫定播放 |
resume() | 重新從頭開始播放 |
seekTo() | 從指定位置開始播放 |
isPlaying() | 判斷當前是否正在播放視頻 |
getDuration() | 獲取載入視頻的播放時長 |
- 做個小Demo練練手吧:
布局文件里放了三個Button,分別為播放,暫停诗鸭,重新播放染簇,在下面是一個VideoView控件,上代碼:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_play"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Play"
android:textAllCaps="false" />
<Button
android:id="@+id/btn_pause"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Pause"
android:textAllCaps="false" />
<Button
android:id="@+id/btn_replay"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Replay"
android:textAllCaps="false" />
</LinearLayout>
<VideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
再看完整java代碼實例:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private VideoView videoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//在 onCreate 里强岸,對界面的按鈕和顯示位置實例化锻弓,并檢查權限
videoView = (VideoView)findViewById(R.id.video_view);
Button btn_play = (Button)findViewById(R.id.btn_play);
Button btn_pause = (Button)findViewById(R.id.btn_pause);
Button btn_replay = (Button)findViewById(R.id.btn_replay);
btn_play.setOnClickListener(this);
btn_pause.setOnClickListener(this);
btn_replay.setOnClickListener(this);
if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}else {
initVideoPath();//初始化MediaPlayer
}
}
單獨寫一個方法做視頻播放的初始化
private void initVideoPath() {
File file = new File(Environment.getExternalStorageDirectory(), "movie.mp4");
videoView.setVideoPath(file.getPath());//指定視頻文件路徑
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.setLooping(true);//讓電影循環(huán)播放
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
initVideoPath();
}else{
Toast.makeText(this, "拒絕權限,無法使用程序蝌箍。", Toast.LENGTH_LONG).show();
finish();
}
break;
default:
break;
}
}
在一個 onClick 方法中青灼,統(tǒng)一處理 Play(播放)、Pause(暫停)妓盲、Replay(重新播放)的邏輯杂拨。
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_play:
if(!videoView.isPlaying()){
videoView.start();//播放
}
break;
case R.id.btn_pause:
if(videoView.isPlaying()){
videoView.pause();//暫停
}
break;
case R.id.btn_replay:
if(videoView.isPlaying()){
videoView.resume();//重新播放
}
break;
}
}
由于視頻播放屬于比較占用資源,所以程序最后要釋放資源
//執(zhí)行完畢悯衬,釋放所有資源弹沽。
@Override
protected void onDestroy() {
super.onDestroy();
if(videoView != null){
videoView.suspend();
}
}
}
3、使用MediaPlayer,MediaPlayer優(yōu)點多,靈活性強策橘,但是難度較大炸渡。一般我們都使用surfaceview+mediaplayer的方式來播放視頻,讓我們來好好看看如何使用它:
- 步驟:
1)獲得MediaPlayer實例:
可以使用直接new的方式:
MediaPlayer mp = new MediaPlayer();
也可以使用create的方式丽已,如:
MediaPlayer mp = MediaPlayer.create(this, R.raw.test);//這時就不用調(diào)用setDataSource了
調(diào)用player.setDataSource()方法設置要播放的資源蚌堵,可以是文件、文件路徑沛婴、或者URL吼畏。
MediaPlayer的setDataSource一共四個方法:
setDataSource (String path)
setDataSource (FileDescriptor fd)
setDataSource (Context context, Uri uri)
setDataSource (FileDescriptor fd, long offset, long length)
- 如何設置要播放的文件:
MediaPlayer要播放的文件主要包括3個來源:
a. 用戶在應用中事先自帶的resource資源
例如:MediaPlayer.create(this, R.raw.test);
b. 存儲在SD卡或其他文件路徑下的媒體文件
例如:mp.setDataSource("/sdcard/test.mp3");
c. 網(wǎng)絡上的媒體文件
例如:mp.setDataSource("http://www.citynorth.cn/music/confucius.mp3");(該網(wǎng)址可能已經(jīng)失效)
3)調(diào)用MediaPlayer.setDisplay(holder)設置surfaceHolder,surfaceHolder可以通過surfaceview的getHolder()方法獲得瘸味。
4)調(diào)用MediaPlayer.prepare()來準備宫仗。
5)調(diào)用MediaPlayer.start()來播放視頻够挂。
這是大致步驟旁仿,但只有這些是不夠的
在第二步之前需要確保surfaceHolder已經(jīng)準備好了。因此需要給surfaceHolder設置一個callback孽糖,
調(diào)用addCallback()方法枯冈。Callback 有三個回調(diào)函數(shù),如下:
SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
surfaceCreated()會在SurfaceHolder被創(chuàng)建的時候回調(diào)办悟,在這里可以做一些初始化的操作尘奏,surfaceDestroyed()會在SurfaceHolder被銷毀的時候回調(diào),在這里可以做一些釋放資源的操作病蛉,防止內(nèi)存泄漏炫加。
一般,會在surfaceCreated中給MediaPlayer設置surfaceHolder铺然。
@Override
public void surfaceCreated(SurfaceHolder holder) {
player.setDisplay(holder);
}
那么具體如何操作呢俗孝,看代碼:
public class MainActivity extends AppCompatActivity {
private SurfaceView surfaceView;
private MediaPlayer player;
private SurfaceHolder holder;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
progressBar= (ProgressBar) findViewById(R.id.progressBar);
player=new MediaPlayer();
try {
File file = new File(Environment.getExternalStorageDirectory(),
"2d1c41ae2482271297c2b6b4e6abf2cf.mp4");//播放手機相冊里的視頻
player.setDataSource(file.getPath());
holder=surfaceView.getHolder();
holder.addCallback(new MyCallBack());
//player.prepare();
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
progressBar.setVisibility(View.INVISIBLE);
player.start();
player.setLooping(true);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
private class MyCallBack implements SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder holder) {
player.setDisplay(holder);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
}
MediaPlayer的具體方法介紹:
方法名 | 功能描述 |
---|---|
void setDataSource(String path) | 通過一個具體的路徑來設置MediaPlayer的數(shù)據(jù)源,path可以是本地的一個路徑魄健,也可以是一個網(wǎng)絡路徑 |
void setDataSource(Context context, Uri uri) | 通過給定的Uri來設置MediaPlayer的數(shù)據(jù)源赋铝,這里的Uri可以是網(wǎng)絡路徑或是一個ContentProvider的Uri。 |
void setDataSource(MediaDataSource dataSource) | 通過提供的MediaDataSource來設置數(shù)據(jù)源 |
void setDataSource(FileDescriptor fd) | 通過文件描述符FileDescriptor來設置數(shù)據(jù)源 |
int getCurrentPosition() | 獲取當前播放的位置 |
int getAudioSessionId() | 返回音頻的session ID |
int getDuration() | 得到文件的時間 |
TrackInfo[] getTrackInfo() | 返回一個track信息的數(shù)組 |
boolean isLooping () | 是否循環(huán)播放 |
boolean isPlaying() | 是否正在播放 |
void pause() | 暫停 |
void start() | 開始 |
void stop() | 停止 |
void prepare() | 同步的方式裝載流媒體文件沽瘦。 |
void prepareAsync() | 異步的方式裝載流媒體文件革骨。 |
void reset() | 重置MediaPlayer至未初始化狀態(tài)。 |
void release () | 回收流媒體資源析恋。 |
void seekTo(int msec) | 指定播放的位置(以毫秒為單位的時間) |
void setAudioStreamType(int streamtype) | 指定流媒體類型 |
void setLooping(boolean looping) | 設置是否單曲循環(huán) |
void setNextMediaPlayer(MediaPlayer next) | 當 當前這個MediaPlayer播放完畢后良哲,MediaPlayer next開始播放 |
void setWakeMode(Context context, int mode) | 設置CPU喚醒的狀態(tài)。 |
setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) | 網(wǎng)絡流媒體的緩沖變化時回調(diào) |
setOnCompletionListener(MediaPlayer.OnCompletionListener listener) | 網(wǎng)絡流媒體播放結束時回調(diào) |
setOnErrorListener(MediaPlayer.OnErrorListener listener) | 發(fā)生錯誤時回調(diào) |
setOnPreparedListener(MediaPlayer.OnPreparedListener listener) | 當裝載流媒體完畢的時候回調(diào)助隧。 |
用MediaPlayer播放音頻
音頻一般也是用MediaPlayer播放的筑凫,MediaPlayer的使用上面已經(jīng)講過了,在音頻的使用和視頻大同小異,所以我們不再贅述漏健,實戰(zhàn)感受一下吧嚎货。
我們來寫個播放音頻的項目試試
- 布局文件很簡單,就三個Button蔫浆,分別為播放殖属,暫停,停止瓦盛。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_play"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="點擊播放"/>
<Button
android:id="@+id/btn_pause"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="點擊暫停"/>
<Button
android:id="@+id/btn_stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="點擊停止播放"/>
</LinearLayout>
- 再到java文件里實現(xiàn)代碼:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button playBtn,resumeBtn,pauseBtn;
private MediaPlayer mediaPlayer ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pauseBtn = findViewById(R.id.btn_pause);
stopBtn = findViewById(R.id.btn_stop);
playBtn = findViewById(R.id.btn_play);
playBtn.setOnClickListener(this);
pauseBtn.setOnClickListener(this);
stopBtn.setOnClickListener(this);
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this,new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE
},1);
}else {
init();
}
}
private void init(){
try{
File file = new File(Envioronment.getExternalStorageDirectory(),"2d1c41ae2482271297c2b6b4e6abf2cf.mp4");
mediaPlayer.setDataSource(file.getPath());
mediaPlayer.setprepare();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull
int[] grantResults) {
switch (requestCode){
case 1:
if (grantResults.length >0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED){
init();
}else{
Toast.makeText(this,"拒絕權限將無法使用程序",
Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
}
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_play:
if (!mediaPlayer.isPlaying()){
mediaPlayer.start();//開始播放
}
break;
case R.id.btn_pause:
if (mediaPlayer.isPlaying()){
mediaPlayer.pause();//暫停播放
}
break;
case R.id.btn_stop:
if (mediaPlayer.isPlaying()){
mediaPlayer.reset();//停止播放
init();
}
break;
default:
break;
}
}
//釋放相關資源
@Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null){
mediaPlayer.stop();
mediaPlayer.release();
}
}
}
- 最后千萬不要忘了權限聲明