传统的VideoView是基于SurfaceView实现的,SurfaceView是在屏幕上指定区域新加的一个绘制区域,不在layout布局上,不受布局限制,绘制效率高,但在ListView等可滑动布局中使用时,会有一定的延时黑影,快速拖动时、低端机上出现的很明显。为解决这个问题,下面基于TextureView重写VideoView--TextureVideoView。
1.查看VideoView源码,发现它是直接继承于SurfaceView,实现MediaPlayerControl接口的,所以我们类似的实现它。好,现在的代码长这样子。
/**
* 基于texture的播放器。可放在listview的item中
*
* Created by cailingxiao on 2017/9/26.
*/
public class TextureVideoView extends TextureView implements MediaController.MediaPlayerControl {
public TextureVideoView(Context context) {
super(context);
}
public TextureVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TextureVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void start() {
}
@Override
public void pause() {
}
@Override
public int getDuration() {
return 0;
}
@Override
public int getCurrentPosition() {
return 0;
}
@Override
public void seekTo(int pos) {
}
@Override
public boolean isPlaying() {
return false;
}
@Override
public int getBufferPercentage() {
return 0;
}
@Override
public boolean canPause() {
return false;
}
@Override
public boolean canSeekBackward() {
return false;
}
@Override
public boolean canSeekForward() {
return false;
}
@Override
public int getAudioSessionId() {
return 0;
}
}
2.复制下VideoView通用逻辑。调整下面几个地方:
2.1 将SurfaceView相关的地方删除;
2.2 将subtitle相关的东西删除;
2.3 在init中加入对TextureView的初始化,添加监听SurfaceTextureListener并实现;
2.4 增加对尺寸变动的支持,之前surfaceView里面有setFixedSize方法来修改大小,所以我们也需要实现个;
最终代码:
public class TextureVideoView extends TextureView implements MediaController.MediaPlayerControl {
private static final String TAG = "VideoView";
// all possible internal states
private static final int STATE_ERROR = -1;
private static final int STATE_IDLE = 0;
private static final int STATE_PREPARING = 1;
private static final int STATE_PREPARED = 2;
private static final int STATE_PLAYING = 3;
private static final int STATE_PAUSED = 4;
private static final int STATE_PLAYBACK_COMPLETED = 5;
// settable by the client
private Uri mUri;
private Map mHeaders;
// mCurrentState is a VideoView object's current state.
// mTargetState is the state that a method caller intends to reach.
// For instance, regardless the VideoView object's current state,
// calling pause() intends to bring the object to a target state
// of STATE_PAUSED.
private int mCurrentState = STATE_IDLE;
private int mTargetState = STATE_IDLE;
// All the stuff we need for playing and showing a video
private MediaPlayer mMediaPlayer = null;
private int mAudioSession;
private int mVideoWidth;
private int mVideoHeight;
private int mSurfaceWidth;
private int mSurfaceHeight;
private MediaController mMediaController;
private MediaPlayer.OnCompletionListener mOnCompletionListener;
private MediaPlayer.OnPreparedListener mOnPreparedListener;
private int mCurrentBufferPercentage;
private MediaPlayer.OnErrorListener mOnErrorListener;
private MediaPlayer.OnInfoListener mOnInfoListener;
private int mSeekWhenPrepared; // recording the seek position while preparing
private boolean mCanPause;
private boolean mCanSeekBack;
private boolean mCanSeekForward;
private Context mContext;
private SurfaceTexture mSurfaceTexture;
public TextureVideoView(Context context) {
this(context, null);
}
public TextureVideoView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TextureVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public TextureVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
// + MeasureSpec.toString(heightMeasureSpec) + ")");
int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
if (mVideoWidth > 0 &