Android列表嵌入视频播放
16lz
2021-01-26
最近在写一个和视频有关的项目,遇到了这个问题,开始使用ListView中嵌入MediaPlayer和TextureView老是出问题,播放的时候item会出现错乱的现象,原因在于使用ViewHolder复用View导致的,如果每次都重新加载View就不会出问题了,这个demo中没有使用ListView,使用了android.support.v7.widget.RecyclerView,达到了预期的目的,希望对正在迷茫中的你有所帮助。
在一个列表视频交流群( 290087364)中找到了一个Demo,然后在此基础上进行了修改,感谢群主的无私贡献,我也不能太自私了,就贴出来,希望能抛砖引玉,给大家带来一点的帮助。
首先看一下,重写的一个TextureView,代码中没有注释,代码量比较少,很容易理解,TextureVideoView主要用于控制视频的播放。
package com.example.textureviewdemo;import android.annotation.SuppressLint;import android.content.Context;import android.graphics.SurfaceTexture;import android.media.MediaPlayer;import android.media.MediaPlayer.OnBufferingUpdateListener;import android.media.MediaPlayer.OnInfoListener;import android.util.AttributeSet;import android.view.Surface;import android.view.TextureView;import android.view.TextureView.SurfaceTextureListener;@SuppressLint("NewApi") public class TextureVideoView extends TextureView implements SurfaceTextureListener {private MediaPlayer mediaPlayer;private Context context;MediaState mediaState;public MediaPlayer getMediaPlayer() {return mediaPlayer;}public interface OnStateChangeListener{public void onSurfaceTextureDestroyed(SurfaceTexture surface);public void onBuffering();public void onPlaying();public void onSeek(int max,int progress);public void onStop();}OnStateChangeListener onStateChangeListener;public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) {this.onStateChangeListener = onStateChangeListener;}//监听视频的缓冲状态private OnInfoListener onInfoListener=new OnInfoListener() {@Overridepublic boolean onInfo(MediaPlayer mp, int what, int extra) {if(onStateChangeListener!=null){onStateChangeListener.onPlaying();if(what==MediaPlayer.MEDIA_INFO_BUFFERING_START){onStateChangeListener.onBuffering();}else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {onStateChangeListener.onPlaying();} }return false;}};//视频缓冲进度更新private OnBufferingUpdateListener bufferingUpdateListener=new OnBufferingUpdateListener() {@Overridepublic void onBufferingUpdate(MediaPlayer mp, int percent) {if(onStateChangeListener!=null){if(mediaState==MediaState.PLAYING){onStateChangeListener.onSeek(mediaPlayer.getDuration(), mediaPlayer.getCurrentPosition());}}}};public TextureVideoView(Context context, AttributeSet attrs) {super(context, attrs);this.context = context;init();}public void init() {setSurfaceTextureListener(this);}@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,int height) {Surface surface = new Surface(surfaceTexture);if(mediaPlayer==null){if(mediaPlayer == null){mediaPlayer = new MediaPlayer();}mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mediaPlayer) { mediaPlayer.start(); mediaState=MediaState.PLAYING; } });mediaPlayer.setOnInfoListener(onInfoListener);mediaPlayer.setOnBufferingUpdateListener(bufferingUpdateListener);}mediaPlayer.setSurface(surface);mediaState=MediaState.INIT;}//停止播放public void stop(){new Thread(new Runnable() {@Overridepublic void run() {try {if(mediaState==MediaState.INIT){return;}if(mediaState==MediaState.PREPARING){mediaPlayer.reset();mediaState=MediaState.INIT;System.out.println("prepare->reset");return;}if(mediaState==MediaState.PAUSE){mediaPlayer.stop();mediaPlayer.reset();mediaState=MediaState.INIT;System.out.println("pause->init");return ;}if(mediaState==MediaState.PLAYING){mediaPlayer.pause();mediaPlayer.stop();mediaPlayer.reset();mediaState=MediaState.INIT;System.out.println("playing->init");return ;}} catch (Exception e) {mediaPlayer.reset();mediaState=MediaState.INIT;}finally{if(onStateChangeListener!=null){onStateChangeListener.onStop();}}}}).start();}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {if(onStateChangeListener!=null){onStateChangeListener.onSurfaceTextureDestroyed(surface);}return false;}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,int height) {}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture surface) {}//开始播放视频public void play(String videoUrl) {if(mediaState==MediaState.PREPARING){stop();return;}mediaPlayer.reset();mediaPlayer.setLooping(true);try {mediaPlayer.setDataSource(videoUrl);} catch (Exception e) {e.printStackTrace();}mediaPlayer.prepareAsync();mediaState=MediaState.PREPARING;} //暂停播放public void pause(){mediaPlayer.pause();mediaState=MediaState.PAUSE;}//播放视频public void start(){mediaPlayer.start();mediaState=MediaState.PLAYING;}//状态(初始化、正在准备、正在播放、暂停、释放)public enum MediaState{INIT,PREPARING,PLAYING,PAUSE,RELEASE;}//获取播放状态public MediaState getState(){return mediaState;}}
下面是适配器,适配器中主要监听列表滚动,当一个Item隐藏之后,对应的TextureView就会销毁,在此时停止播放视频
package com.example.textureviewdemo;import java.util.List;import com.example.textureviewdemo.TextureVideoView.MediaState;import com.example.textureviewdemo.TextureVideoView.OnStateChangeListener;import com.xiaojiang.textureviewdemo.R;import android.content.Context;import android.graphics.SurfaceTexture;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.RecyclerView.ViewHolder;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.View.OnClickListener;import android.widget.ImageView;import android.widget.ProgressBar;public class VideoAdapter extends RecyclerView.Adapter{List mVideos;Context mContext;private VideoViewHolder lastPlayVideo=null;public VideoAdapter(Context context,List videos) {mContext=context;mVideos=videos;}class VideoViewHolder extends ViewHolder{public VideoViewHolder(View itemView) {super(itemView);}TextureVideoView videoView;ImageView imvPreview;ImageView imvPlay;ProgressBar pbWaiting;ProgressBar pbProgressBar;}@Overridepublic int getItemCount() {return mVideos.size();}@Overridepublic void onBindViewHolder(final VideoViewHolder viewHolder, final int position) {viewHolder.videoView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if(lastPlayVideo==null){lastPlayVideo=viewHolder;}else{if(!viewHolder.equals(lastPlayVideo)){lastPlayVideo.videoView.stop();lastPlayVideo.pbWaiting.setVisibility(View.GONE);lastPlayVideo.imvPlay.setVisibility(View.VISIBLE);lastPlayVideo=viewHolder;}}TextureVideoView textureView = (TextureVideoView) v;if(textureView.getState()==MediaState.INIT||textureView.getState()==MediaState.RELEASE){textureView.play(mVideos.get(position));viewHolder.pbWaiting.setVisibility(View.VISIBLE);viewHolder.imvPlay.setVisibility(View.GONE);}else if(textureView.getState()==MediaState.PAUSE){textureView.start();viewHolder.pbWaiting.setVisibility(View.GONE);viewHolder.imvPlay.setVisibility(View.GONE);}else if(textureView.getState()==MediaState.PLAYING){textureView.pause();viewHolder.pbWaiting.setVisibility(View.GONE);viewHolder.imvPlay.setVisibility(View.VISIBLE);}else if(textureView.getState()==MediaState.PREPARING){textureView.stop();viewHolder.pbWaiting.setVisibility(View.GONE);viewHolder.imvPlay.setVisibility(View.VISIBLE);}}});viewHolder.videoView.setOnStateChangeListener(new OnStateChangeListener() {@Overridepublic void onSurfaceTextureDestroyed(SurfaceTexture surface) {viewHolder.videoView.stop();viewHolder.pbWaiting.setVisibility(View.GONE);viewHolder.imvPlay.setVisibility(View.VISIBLE);viewHolder.pbProgressBar.setMax(1);viewHolder.pbProgressBar.setProgress(0);}@Overridepublic void onPlaying() {viewHolder.pbWaiting.setVisibility(View.GONE);viewHolder.imvPlay.setVisibility(View.GONE);}@Overridepublic void onBuffering() {viewHolder.pbWaiting.setVisibility(View.VISIBLE);viewHolder.imvPlay.setVisibility(View.GONE);}@Overridepublic void onSeek(int max,int progress){viewHolder.pbProgressBar.setMax(max);viewHolder.pbProgressBar.setProgress(progress);}@Overridepublic void onStop() {viewHolder.pbProgressBar.setMax(1);viewHolder.pbProgressBar.setProgress(0);}});}@Overridepublic VideoViewHolder onCreateViewHolder(ViewGroup root, int position) {View containerView=LayoutInflater.from(mContext).inflate(R.layout.videoitem, root, false);VideoViewHolder videoViewHolder=new VideoViewHolder(containerView);videoViewHolder.videoView=(TextureVideoView) containerView.findViewById(R.id.textureview);videoViewHolder.imvPreview=(ImageView) containerView.findViewById(R.id.imv_preview);videoViewHolder.imvPlay=(ImageView) containerView.findViewById(R.id.imv_video_play);videoViewHolder.pbWaiting=(ProgressBar) containerView.findViewById(R.id.pb_waiting);videoViewHolder.pbProgressBar=(ProgressBar) containerView.findViewById(R.id.progress_progressbar);return videoViewHolder;}}
相关的布局文件以及Activity文件就不贴出来了,有兴趣的可以到此处下载源码:
https://github.com/kidloserme/ListVideoPlayer
CSDN下载地址:http://download.csdn.net/detail/u013758734/9248269
更多相关文章
- Android实现实时视频通话或监控方案
- 浅谈关于listview和button控件的背景
- Android接收UDP TS流实现边缓存边播放
- Android(安卓)开机视频
- Rexsee API介绍:Android视频播放,Rexsee的VideoPlayer函数说明与源
- Android文件命名规范
- Android(安卓)开发学习进程0.15 adb cardview framelayout 控件
- android 4.4 以上沉浸式状态栏和沉浸式导航栏管理,一句代码轻松实
- Android小程序实现音乐播放列表