1. VideoViewの使用
VideoView
を継承しSurfaceView
、組み合わせMediaPlayerControl
に相当するインターフェースを実装します。MediaPlayer+SurfaceView
については、こちらをMediaPlayer
参照してください。
レイアウトファイルに追加しますVideoView
<VideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
でActivity
ビデオを再生する
var mVideoView = findViewById(R.id.video_view)
mVideoView.setVideoURI(Uri.parse(uri))
// 设置控制器
mVideoView.setMediaController(MediaController(this))
mVideoView.start()
2. VideoViewのメインメソッド
メインメソッド
// 设置视频源
void setVideoPath(String path)
void setVideoURI(Uri uri)
void setVideoURI(Uri uri, Map<String, String> headers)
// 恢复,从头播放
void resume()
// 播放
void start()
// 暂停
void pause()
// 释放资源
void suspend()
// 停止播放
void stopPlayback()
// 视频时长
int getDuration()
// 当前位置
int getCurrentPosition()
// 跳转到指定时间
void seekTo(int msec)
// 是否正在播放
boolean isPlaying()
// 设置控制器
void setMediaController(MediaController controller)
3. VideoView のソースコード分析
VideoView
現在の状態とターゲットの状態の 2 つの状態がmCurrentState
ありmTargetState
、初期値は両方でありSTATE_IDLE
、再生時にこれら 2 つの状態に関連付けられます。
VideoView
内部のsetVideoXXX
およびresume
メソッドは直接呼び出されopenVideo
、openVideo
メソッド内で呼び出してMediaPlayer
ビデオを再生します。リソースを再生する準備が
mPreparedListener
できたら、設定されている場合は、指定された時間にジャンプします。に設定されている場合は、直接再生します。MediaPlayer
mSeekWhenPrepared
mTargetState
STATE_PLAYING
public void setVideoPath(String path) {
setVideoURI(Uri.parse(path));
}
public void setVideoURI(Uri uri) {
setVideoURI(uri, null);
}
public void setVideoURI(Uri uri, Map<String, String> headers) {
mUri = uri;
mHeaders = headers;
mSeekWhenPrepared = 0;
openVideo();
requestLayout();
invalidate();
}
public void resume() {
openVideo();
}
private void openVideo() {
if (mUri == null || mSurfaceHolder == null) {
// not ready for playback just yet, will try again later
return;
}
// 清空mCurrentState,但保留mTargetState
release(false);
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
mMediaPlayer.setDisplay(mSurfaceHolder);
mMediaPlayer.prepareAsync();
mCurrentState = STATE_PREPARING;
}
private void release(boolean cleartargetstate) {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
mPendingSubtitleTracks.clear();
mCurrentState = STATE_IDLE;
if (cleartargetstate) {
mTargetState = STATE_IDLE;
}
if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
mAudioManager.abandonAudioFocus(null);
}
}
}
MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mCurrentState = STATE_PREPARED;
if (mOnPreparedListener != null) {
mOnPreparedListener.onPrepared(mMediaPlayer);
}
int seekToPosition = mSeekWhenPrepared;
if (seekToPosition != 0) {
seekTo(seekToPosition);
}
if (mVideoWidth != 0 && mVideoHeight != 0) {
getHolder().setFixedSize(mVideoWidth, mVideoHeight);
if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
if (mTargetState == STATE_PLAYING) {
start();
} else if (!isPlaying() &&
(seekToPosition != 0 || getCurrentPosition() > 0)) {
if (mMediaController != null) {
mMediaController.show(0);
}
}
}
} else {
if (mTargetState == STATE_PLAYING) {
start();
}
}
}
};
VideoView
内部のメソッドはstart
、直接呼び出される対応するメソッドです。再生を停止し、リソースを解放しますが、変更されます。pause
MediaPlayer
suspend
stopPlayback
stopPlayback
mTargetState
@Override
public void start() {
if (isInPlaybackState()) {
mMediaPlayer.start();
mCurrentState = STATE_PLAYING;
}
mTargetState = STATE_PLAYING;
}
@Override
public void pause() {
if (isInPlaybackState()) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
mCurrentState = STATE_PAUSED;
}
}
mTargetState = STATE_PAUSED;
}
public void suspend() {
release(false);
}
public void stopPlayback() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
mAudioManager.abandonAudioFocus(null);
}
}
getDuration
、getCurrentPosition
および対応する呼び出しメソッドでseekTo
もあり、状態検証の層をラップするだけであり、直接呼び出しよりも合理的です。MediaPlayer
public int getDuration() {
if (isInPlaybackState()) {
return mMediaPlayer.getDuration();
}
return -1;
}
@Override
public int getCurrentPosition() {
if (isInPlaybackState()) {
return mMediaPlayer.getCurrentPosition();
}
return 0;
}
@Override
public void seekTo(int msec) {
if (isInPlaybackState()) {
mMediaPlayer.seekTo(msec);
mSeekWhenPrepared = 0;
} else {
mSeekWhenPrepared = msec;
}
}
4.MediaControllerコントローラー
MediaController
コントローラーはVideoView
デフォルトのコントローラーです。
public void setMediaController(MediaController controller) {
if (mMediaController != null) {
mMediaController.hide();
}
mMediaController = controller;
attachMediaController();
}
private void attachMediaController() {
if (mMediaPlayer != null && mMediaController != null) {
mMediaController.setMediaPlayer(this);
View anchorView = this.getParent() instanceof View ?
(View)this.getParent() : this;
mMediaController.setAnchorView(anchorView);
mMediaController.setEnabled(isInPlaybackState());
}
}
MediaController
作成インターフェイスには通常、左から右に巻き戻し、再生/一時停止、早送りの 3 つのボタンが含まれています。下部には左から右に、現在時刻、進行状況バー、合計再生時間が表示されます。プログレスバーをドラッグすると、指定した時間にジャンプします。
public void setMediaPlayer(MediaPlayerControl player) {
mPlayer = player;
updatePausePlay();
}
public void setAnchorView(View view) {
if (mAnchor != null) {
mAnchor.removeOnLayoutChangeListener(mLayoutChangeListener);
}
mAnchor = view;
if (mAnchor != null) {
mAnchor.addOnLayoutChangeListener(mLayoutChangeListener);
}
FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
removeAllViews();
View v = makeControllerView();
addView(v, frameParams);
}
setPrevNextListeners
メソッドを呼び出した後、next
と の値に応じて両側にボタンを追加しますprev
。
public void setPrevNextListeners(View.OnClickListener next, View.OnClickListener prev)
以下のように表示します