在我上一篇中实现了VideoView在ViewPager+Fragment中实现图片和视频混播的效果,参见Android 图片和视屏混播的实现和坑.但是在实际中发现有时会出现ANR异常,最后经过分析发现这是由于MediaPlayer是基于状态机实现的,有一些操作,例如reset(),release()等等都是同步实现,所以频繁操作会引起ANR,解决方案就是将所用针对mediaPlayer的操作放到单独现场handler中去同一处理,达到同步处理的目的。
修改前的代码:
public void startPlayer() {
if (null != mVideoView) {
mVideoView.seekTo(currentPosition);
mVideoView.start();
}
}
public void circulationPlayer(){
if (null != mVideoView) {
mVideoView.setVideoPath(bannerBean.getUrl());
mVideoView.start();
}
}
private void stopPlayer() {
if (null != mVideoView) {
mVideoView.stopPlayback();
}
}
public boolean isPlaying(){
if(null != mVideoView){
return mVideoView.isPlaying();
}
return false;
}
private void pausePlayer() {
if (null != mVideoView) {
playerPaused = true;
this.currentPosition = mVideoView.getCurrentPosition();
mVideoView.pause();
}
}
@Override
public void onResume() {
super.onResume();
if(playerPaused){
startPlayer();
}
}
@Override
public void onPause() {
super.onPause();
pausePlayer();
}
@Override
public void onDestroy() {
super.onDestroy();
stopPlayer();
Log.e(TAG, "onDestroy=" + bannerBean.getUrl());
}
修改后的代码:
/**
* 使用Handler是为了避免出现ANR异常
*/
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case STOP_PLAYER:
stopPlayer();
break;
case START_PLAYER:
startPlayer();
break;
case PAUSE_PLAYER:
pausePlayer();
break;
case SET_VIDEO_URL:
setVideoUrl();
startPlayer();
break;
}
super.handleMessage(msg);
}
};
private void setVideoUrl() {
String url = bannerBean.getUrl();
mUrl = url;
//播放本地视频
mVideoView.setVideoURI(Uri.parse(url));
}
public void startPlayer() {
if (null != mVideoView) {
mVideoView.seekTo(currentPosition);
mVideoView.start();
}
}
public void circulationPlayer(){
/*if (null != mVideoView) {
mVideoView.setVideoPath(bannerBean.getUrl());
mVideoView.start();
}*/
sendStartVideoMsg(true);
}
private void stopPlayer() {
if (null != mVideoView) {
mVideoView.stopPlayback();
handler.removeCallbacksAndMessages(null);
}
}
public boolean isPlaying(){
if(null != mVideoView){
return mVideoView.isPlaying();
}
return false;
}
private void pausePlayer() {
if (null != mVideoView) {
playerPaused = true;
this.currentPosition = mVideoView.getCurrentPosition();
mVideoView.pause();
}
}
private void sendStartVideoMsg() {
sendStartVideoMsg(false);
}
private void sendStartVideoMsg(boolean isHasUrl) {
removeMessages();
if (!handler.hasMessages(START_PLAYER)) {
if (null != mVideoView) {
if (isHasUrl) {
try {
mVideoView.setVideoURI(Uri.parse(mUrl));
} catch (Exception e) {
e.printStackTrace();
}
}
handler.sendEmptyMessage(START_PLAYER);
}
}
}
private void sendStopVideoMsg() {
removeMessages();
if (!handler.hasMessages(STOP_PLAYER)) {
if (null != mVideoView) {
handler.sendEmptyMessage(STOP_PLAYER);
}
}
}
private void sendPauseVideoMsg() {
removeMessages();
if (!handler.hasMessages(PAUSE_PLAYER)) {
if (null != mVideoView) {
handler.sendEmptyMessage(PAUSE_PLAYER);
}
}
}
private void sendSetVideoUrlMsg() {
removeMessages();
if (!handler.hasMessages(SET_VIDEO_URL)) {
if (null != mVideoView) {
Log.e(TAG, "sendSetVideoUrlMsg------");
handler.sendEmptyMessage(SET_VIDEO_URL);
}
}
}
private void removeMessages() {
if (handler.hasMessages(START_PLAYER)) {
handler.removeMessages(START_PLAYER);
}
if (handler.hasMessages(STOP_PLAYER)) {
handler.removeMessages(STOP_PLAYER);
}
if (handler.hasMessages(PAUSE_PLAYER)) {
handler.removeMessages(PAUSE_PLAYER);
}
if (handler.hasMessages(SET_VIDEO_URL)) {
handler.removeMessages(SET_VIDEO_URL);
}
}
@Override
public void onResume() {
super.onResume();
if(playerPaused){
// startPlayer();
sendStartVideoMsg();
}
}
@Override
public void onPause() {
super.onPause();
// pausePlayer();
sendPauseVideoMsg();
}
@Override
public void onDestroy() {
super.onDestroy();
//stopPlayer();
sendStopVideoMsg();
Log.e(TAG, "onDestroy=" + bannerBean.getUrl());
}
完整的代码:
public class ImageVideoFragment extends Fragment {
private static final String TAG = ImageVideoFragment.class.getSimpleName();
private OnVideoCompletionListener listener;
private VideoView mVideoView;
private BannerBean bannerBean;
private FrameLayout waitLoading;
private int currentPosition;
private boolean playerPaused;
private String mUrl;
private final int STOP_PLAYER = 0x2000;
private final int START_PLAYER = 0x2001;
private final int PAUSE_PLAYER = 0x2002;
private final int SET_VIDEO_URL = 0x2003;
/**
* 使用Handler是为了避免出现ANR异常
*/
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case STOP_PLAYER:
stopPlayer();
break;
case START_PLAYER:
startPlayer();
break;
case PAUSE_PLAYER:
pausePlayer();
break;
case SET_VIDEO_URL:
setVideoUrl();
startPlayer();
break;
}
super.handleMessage(msg);
}
};
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
bannerBean = (BannerBean) bundle.getSerializable("bannerBean");
Log.e(TAG, "type=" + bannerBean.getType() + ",url=" + bannerBean.getUrl());
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view;
if (bannerBean != null) {
int type = bannerBean.getType();
if (type == 0) {
view = LayoutInflater.from(getActivity()).inflate(R.layout.item_image_view, container, false);
ImageView imageView = view.findViewById(R.id.iv);
Glide.with(container.getContext()).load(bannerBean.getUrl())
.into(imageView);
} else {
view = LayoutInflater.from(getActivity()).inflate(R.layout.item_video_view, container, false);
mVideoView = view.findViewById(R.id.video_view);
waitLoading = view.findViewById(R.id.wait_loading_layout);
initData();
}
} else {
view = LayoutInflater.from(getActivity()).inflate(R.layout.item_image_view, container, false);
}
return view;
}
private void initData() {
if (null != mVideoView) {
// mVideoView.setVideoPath(bannerBean.getUrl());
sendSetVideoUrlMsg();
mVideoView.setMediaController(new MediaController(getActivity()));
mVideoView.requestFocus();
mVideoView.setVideoURI(Uri.parse(bannerBean.getUrl()));
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mVideoView.stopPlayback();
if (null != listener) {
listener.onVideoCompletion(mp);
}
}
});
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
Log.e(TAG, "视频加载完成" + bannerBean.getUrl());
mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
waitLoading.setVisibility(View.GONE);
mVideoView.setVisibility(View.VISIBLE);
/*if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
waitLoading.setVisibility(View.GONE);
mVideoView.setVisibility(View.VISIBLE);
return true;
}*/
return false;
}
});
}
});
mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e(TAG, "视频播放出错了-what="+what+",extra="+extra);
mVideoView.stopPlayback();
if(null != listener){
listener.onError(mp);
}
if(what == MediaPlayer.MEDIA_ERROR_SERVER_DIED){
//媒体服务器挂掉了。此时,程序必须释放MediaPlayer 对象,并重新new 一个新的。
Log.e(TAG, "媒体服务器挂掉了");
}else if(what == MediaPlayer.MEDIA_ERROR_UNKNOWN){
if(extra == MediaPlayer.MEDIA_ERROR_IO){
//文件不存在或错误,或网络不可访问错误
Log.e(TAG, "文件不存在或错误,或网络不可访问错误");
}else if(extra == MediaPlayer.MEDIA_ERROR_TIMED_OUT){
//超时
Log.e(TAG, "超时");
}
}
return true;
}
});
// startPlayer();
}
}
private void setVideoUrl() {
String url = bannerBean.getUrl();
mUrl = url;
//播放本地视频
mVideoView.setVideoURI(Uri.parse(url));
}
public void startPlayer() {
if (null != mVideoView) {
mVideoView.seekTo(currentPosition);
mVideoView.start();
}
}
public void circulationPlayer(){
/*if (null != mVideoView) {
mVideoView.setVideoPath(bannerBean.getUrl());
mVideoView.start();
}*/
sendStartVideoMsg(true);
}
private void stopPlayer() {
if (null != mVideoView) {
mVideoView.stopPlayback();
handler.removeCallbacksAndMessages(null);
}
}
public boolean isPlaying(){
if(null != mVideoView){
return mVideoView.isPlaying();
}
return false;
}
private void pausePlayer() {
if (null != mVideoView) {
playerPaused = true;
this.currentPosition = mVideoView.getCurrentPosition();
mVideoView.pause();
}
}
private void sendStartVideoMsg() {
sendStartVideoMsg(false);
}
private void sendStartVideoMsg(boolean isHasUrl) {
removeMessages();
if (!handler.hasMessages(START_PLAYER)) {
if (null != mVideoView) {
if (isHasUrl) {
try {
mVideoView.setVideoURI(Uri.parse(mUrl));
} catch (Exception e) {
e.printStackTrace();
}
}
handler.sendEmptyMessage(START_PLAYER);
}
}
}
private void sendStopVideoMsg() {
removeMessages();
if (!handler.hasMessages(STOP_PLAYER)) {
if (null != mVideoView) {
handler.sendEmptyMessage(STOP_PLAYER);
}
}
}
private void sendPauseVideoMsg() {
removeMessages();
if (!handler.hasMessages(PAUSE_PLAYER)) {
if (null != mVideoView) {
handler.sendEmptyMessage(PAUSE_PLAYER);
}
}
}
private void sendSetVideoUrlMsg() {
removeMessages();
if (!handler.hasMessages(SET_VIDEO_URL)) {
if (null != mVideoView) {
Log.e(TAG, "sendSetVideoUrlMsg------");
handler.sendEmptyMessage(SET_VIDEO_URL);
}
}
}
private void removeMessages() {
if (handler.hasMessages(START_PLAYER)) {
handler.removeMessages(START_PLAYER);
}
if (handler.hasMessages(STOP_PLAYER)) {
handler.removeMessages(STOP_PLAYER);
}
if (handler.hasMessages(PAUSE_PLAYER)) {
handler.removeMessages(PAUSE_PLAYER);
}
if (handler.hasMessages(SET_VIDEO_URL)) {
handler.removeMessages(SET_VIDEO_URL);
}
}
@Override
public void onResume() {
super.onResume();
if(playerPaused){
// startPlayer();
sendStartVideoMsg();
}
}
@Override
public void onPause() {
super.onPause();
// pausePlayer();
sendPauseVideoMsg();
}
@Override
public void onDestroy() {
super.onDestroy();
//stopPlayer();
sendStopVideoMsg();
Log.e(TAG, "onDestroy=" + bannerBean.getUrl());
}
public interface OnVideoCompletionListener {
void onVideoCompletion(MediaPlayer mp);
void onError(MediaPlayer mp);
}
public void setOnVideoCompletionListener(OnVideoCompletionListener listener) {
this.listener = listener;
}
}
项目地址