2025-05-25

承香墨影

Android–使用VideoView播放視頻

 

前言

 

  之前有講過如何使用SurfaceView配合MediaPlayer播放視頻,其實Android還為開發人員提供瞭另外一種更簡單的播放視頻媒體的方式,那就是VideoView,本篇博客就來講講VideoView如何播放視頻,最後將以一個簡單的Demo演示。

 

  本篇博客的主要內容如下:

 

VideoView

VideoView簡單的Demo

MediaController

MediaController簡單的Demo

 

 

VideoView

 

  VideoView,用於播放一段視頻媒體,它繼承瞭SurfaceView,位於"android.widget.VideoView",是一個視頻控件。

 

  既然是播放一段視頻,那麼不可避免的要涉及到一些開始、暫停、停止等操作,VideoView也為開發人員提供瞭對應的方法,這裡簡單介紹一些常用的:

 

int getCurrentPosition():獲取當前播放的位置。

int getDuration():獲取當前播放視頻的總長度。

isPlaying():當前VideoView是否在播放視頻。

void pause():暫停

void seekTo(int msec):從第幾毫秒開始播放。

void resume():重新播放。

void setVideoPath(String path):以文件路徑的方式設置VideoView播放的視頻源。

void setVideoURI(Uri uri):以Uri的方式設置VideoView播放的視頻源,可以是網絡Uri或本地Uri。

void start():開始播放。

void stopPlayback():停止播放。

setMediaController(MediaController controller):設置MediaController控制器。

setOnCompletionListener(MediaPlayer.onCompletionListener l):監聽播放完成的事件。

setOnErrorListener(MediaPlayer.OnErrorListener l):監聽播放發生錯誤時候的事件。

setOnPreparedListener(MediaPlayer.OnPreparedListener l)::監聽視頻裝載完成的事件。

  上面的一些方法通過方法名就可以瞭解用途。和MediaPlayer配合SurfaceView播放視頻不同,VideoView播放之前無需編碼裝載視頻,它會在start()開始播放的時候自動裝載視頻。並且VideoView在使用完之後,無需編碼回收資源。

 

 

 

VideoView簡單的Demo

 

  VideoView其實沒有什麼難點,通過它自帶的API方法,即可完成一段視頻的播放,無非就是註意它方法的調用時機即可。下面通過一個簡單的Demo,演示VideoView如何播放一段SD卡上的視頻文件。在Demo中提供瞭四個Button,分別表示播放、暫停、重播、停止,並配合進度條顯示。代碼註釋比較完整,細節部分這裡不再累述。

 

  佈局代碼:activity_videoview.xml

 

 View Code

  實現代碼:VideoViewActivity.java

 

復制代碼

  1 package cn.bgxt.videoviewdemo;

  2 

  3 import java.io.File;

  4 

  5 import android.app.Activity;

  6 import android.media.MediaPlayer;

  7 import android.media.MediaPlayer.OnCompletionListener;

  8 import android.media.MediaPlayer.OnErrorListener;

  9 import android.os.Bundle;

 10 import android.util.Log;

 11 import android.view.View;

 12 import android.widget.Button;

 13 import android.widget.EditText;

 14 import android.widget.SeekBar;

 15 import android.widget.Toast;

 16 import android.widget.VideoView;

 17 import android.widget.SeekBar.OnSeekBarChangeListener;

 18 

 19 public class VideoViewActivity extends Activity {

 20     private final String TAG = "main";

 21     private EditText et_path;

 22     private Button btn_play, btn_pause, btn_replay, btn_stop;

 23     private SeekBar seekBar;

 24     private VideoView vv_video;

 25     private boolean isPlaying;

 26 

 27     @Override

 28     protected void onCreate(Bundle savedInstanceState) {

 29         // TODO Auto-generated method stub

 30         super.onCreate(savedInstanceState);

 31         setContentView(R.layout.activity_videoview);

 32 

 33         seekBar = (SeekBar) findViewById(R.id.seekBar);

 34         et_path = (EditText) findViewById(R.id.et_path);

 35         vv_video = (VideoView) findViewById(R.id.vv_videoview);

 36 

 37         btn_play = (Button) findViewById(R.id.btn_play);

 38         btn_pause = (Button) findViewById(R.id.btn_pause);

 39         btn_replay = (Button) findViewById(R.id.btn_replay);

 40         btn_stop = (Button) findViewById(R.id.btn_stop);

 41 

 42         btn_play.setOnClickListener(click);

 43         btn_pause.setOnClickListener(click);

 44         btn_replay.setOnClickListener(click);

 45         btn_stop.setOnClickListener(click);

 46 

 47         // 為進度條添加進度更改事件

 48         seekBar.setOnSeekBarChangeListener(change);

 49     }

 50 

 51     private OnSeekBarChangeListener change = new OnSeekBarChangeListener() {

 52 

 53         @Override

 54         public void onStopTrackingTouch(SeekBar seekBar) {

 55             // 當進度條停止修改的時候觸發

 56             // 取得當前進度條的刻度

 57             int progress = seekBar.getProgress();

 58             if (vv_video != null && vv_video.isPlaying()) {

 59                 // 設置當前播放的位置

 60                 vv_video.seekTo(progress);

 61             }

 62         }

 63 

 64         @Override

 65         public void onStartTrackingTouch(SeekBar seekBar) {

 66 

 67         }

 68 

 69         @Override

 70         public void onProgressChanged(SeekBar seekBar, int progress,

 71                 boolean fromUser) {

 72 

 73         }

 74     };

 75     private View.OnClickListener click = new View.OnClickListener() {

 76 

 77         @Override

 78         public void onClick(View v) {

 79 

 80             switch (v.getId()) {

 81             case R.id.btn_play:

 82                 play(0);

 83                 break;

 84             case R.id.btn_pause:

 85                 pause();

 86                 break;

 87             case R.id.btn_replay:

 88                 replay();

 89                 break;

 90             case R.id.btn_stop:

 91                 stop();

 92                 break;

 93             default:

 94                 break;

 95             }

 96         }

 97     };

 98 

 99     protected void play(int msec) {

100         Log.i(TAG, " 獲取視頻文件地址");

101         String path = et_path.getText().toString().trim();

102         File file = new File(path);

103         if (!file.exists()) {

104             Toast.makeText(this, "視頻文件路徑錯誤", 0).show();

105             return;

106         }

107         

108         Log.i(TAG, "指定視頻源路徑");

109         vv_video.setVideoPath(file.getAbsolutePath());

110         Log.i(TAG, "開始播放");

111         vv_video.start();

112         

113         // 按照初始位置播放

114         vv_video.seekTo(msec);

115         // 設置進度條的最大進度為視頻流的最大播放時長

116         seekBar.setMax(vv_video.getDuration());

117 

118         // 開始線程,更新進度條的刻度

119         new Thread() {

120 

121             @Override

122             public void run() {

123                 try {

124                     isPlaying = true;

125                     while (isPlaying) {

126                         // 如果正在播放,沒0.5.毫秒更新一次進度條

127                         int current = vv_video.getCurrentPosition();

128                         seekBar.setProgress(current);

129 

130                         sleep(500);

131                     }

132                 } catch (Exception e) {

133                     e.printStackTrace();

134                 }

135             }

136         }.start();

137         // 播放之後設置播放按鈕不可用

138         btn_play.setEnabled(false);

139 

140         vv_video.setOnCompletionListener(new OnCompletionListener() {

141 

142             @Override

143             public void onCompletion(MediaPlayer mp) {

144                 // 在播放完畢被回調

145                 btn_play.setEnabled(true);

146             }

147         });

148 

149         vv_video.setOnErrorListener(new OnErrorListener() {

150 

151             @Override

152             public boolean onError(MediaPlayer mp, int what, int extra) {

153                 // 發生錯誤重新播放

154                 play(0);

155                 isPlaying = false;

156                 return false;

157             }

158         });

159     }

160 

161     /**

162      * 重新開始播放

163      */

164     protected void replay() {

165         if (vv_video != null && vv_video.isPlaying()) {

166             vv_video.seekTo(0);

167             Toast.makeText(this, "重新播放", 0).show();

168             btn_pause.setText("暫停");

169             return;

170         }

171         isPlaying = false;

172         play(0);

173 

174     }

175 

176     /**

177      * 暫停或繼續

178      */

179     protected void pause() {

180         if (btn_pause.getText().toString().trim().equals("繼續")) {

181             btn_pause.setText("暫停");

182             vv_video.start();

183             Toast.makeText(this, "繼續播放", 0).show();

184             return;

185         }

186         if (vv_video != null && vv_video.isPlaying()) {

187             vv_video.pause();

188             btn_pause.setText("繼續");

189             Toast.makeText(this, "暫停播放", 0).show();

190         }

191     }

192 

193     /*

194      * 停止播放

195      */

196     protected void stop() {

197         if (vv_video != null && vv_video.isPlaying()) {

198             vv_video.stopPlayback();

199             btn_play.setEnabled(true);

200             isPlaying = false;

201         }

202     }

203 }

復制代碼

  效果展示:

 

 

 

 

 

MediaController

 

  提到VideoView不得不再說一些MediaController。雖然VideoView為我們提供瞭方便的API用於播放、暫停、停止等操作,但是還是需要我們編碼完成,但是如果使用瞭MediaController的話,那麼這些操作都可以省去。

 

  MediaController可以用於配合VideoView播放一段視頻,它為VideoView提供一個懸浮的操作欄,在操作欄中可以對VideoView播放的視頻進行控制,默認情況下,會懸浮顯示三秒。它通過MediaController.setMediaPlayer()方法進行指定需要控制的VideoView,但是僅僅這樣是不夠的,MediaController的控制需要類似於雙向控制,MediaController指定控制的VideoView,VideoView還需要指定那個MediaController來控制它,這需要使用VideoView.setMediaController()方法。

 

  下面介紹一下MediaController的一些常用方法;

 

boolean isShowing():當前懸浮控制欄是否顯示。

void setMediaPlayer(MediaController.MediaPlayerControl player):設置控制的組件。

void setPrevNextListeners(View.OnClickListener next,View.OnClickListener prev):設置上一個視頻、下一個視頻的切換事件。

  通過上面的方法可以看出setMediaPlayer()並非指定的是一個VideoView,而是一個MediaPlayerControl接口,MediaPlayerControl接口內部定義瞭一些播放相關的播放、暫停、停止等操作,而VideoView實現瞭MediaPlayerControl。

 

  默認情況下,如果不通過setPrevNextListeners()設置切換視頻的監聽器,MediaController是不會顯示這兩個按鈕的。

 

 

 

MediaController簡單的Demo

 

  上面已經講過MediaController的一些內容,下面通過一個簡單的Demo來演示一下MediaController控制VideoView播放視頻。

 

  佈局代碼:activity_controller.xml

 

 View Code

  實現代碼:ControllerActivity.java

 

復制代碼

 1 package cn.bgxt.videoviewdemo;

 2 

 3 import java.io.File;

 4 

 5 import android.app.Activity;

 6 import android.os.Bundle;

 7 import android.view.View;

 8 import android.view.View.OnClickListener;

 9 import android.widget.MediaController;

10 import android.widget.Toast;

11 import android.widget.VideoView;

12 

13 public class ControllerActivity extends Activity {

14     private VideoView vv_video;

15     private MediaController mController;

16     

17     @Override

18     protected void onCreate(Bundle savedInstanceState) {

19         super.onCreate(savedInstanceState);

20         setContentView(R.layout.activity_controller);

21         vv_video=(VideoView) findViewById(R.id.vv_video);

22         // 實例化MediaController

23         mController=new MediaController(this);

24         File file=new File("/sdcard/ykzzldx.mp4");

25         if(file.exists()){

26             // 設置播放視頻源的路徑

27             vv_video.setVideoPath(file.getAbsolutePath());

28             // 為VideoView指定MediaController

29             vv_video.setMediaController(mController);

30             // 為MediaController指定控制的VideoView

31             mController.setMediaPlayer(vv_video);

32             // 增加監聽上一個和下一個的切換事件,默認這兩個按鈕是不顯示的

33             mController.setPrevNextListeners(new OnClickListener() {

34                 

35                 @Override

36                 public void onClick(View v) {                    

37                     Toast.makeText(ControllerActivity.this, "下一個",0).show();

38                 }

39             }, new OnClickListener() {

40                 

41                 @Override

42                 public void onClick(View v) {

43                     Toast.makeText(ControllerActivity.this, "上一個",0).show();

44                 }

45             });

46         }

47     }

48 }

復制代碼

 

 

 

 

 

 

  從上面展示的效果可以看出,MediaController不光為我們增加瞭控制欄來控制播放、暫停、快進、快退、切換上一視頻、切換下一視頻,還增加瞭進度條顯示。

 

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *