Android列表嵌入视频播放

最近在写一个和视频有关的项目,遇到了这个问题,开始使用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() {
		@Override
		public 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() {
		@Override
		public 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);
	}

	@Override
	public 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() {
			@Override
			public 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();
	}

	@Override
	public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
		if(onStateChangeListener!=null)
		{
			onStateChangeListener.onSurfaceTextureDestroyed(surface);
		}
		return false;
	}

	@Override
	public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
			int height) {
	}

	@Override
	public 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;
	}

	@Override
	public int getItemCount() {
		return mVideos.size();
	}

	@Override
	public void onBindViewHolder(final VideoViewHolder viewHolder, final int position) {
		viewHolder.videoView.setOnClickListener(new OnClickListener() {
			@Override
			public 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() {
			@Override
			public 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);
			}
			
			@Override
			public void onPlaying() {
				viewHolder.pbWaiting.setVisibility(View.GONE);
				viewHolder.imvPlay.setVisibility(View.GONE);
			}
			
			@Override
			public void onBuffering() {
				viewHolder.pbWaiting.setVisibility(View.VISIBLE);
				viewHolder.imvPlay.setVisibility(View.GONE);
			}
			
			@Override
			public void onSeek(int max,int progress){
				viewHolder.pbProgressBar.setMax(max);
				viewHolder.pbProgressBar.setProgress(progress);
			}

			@Override
			public void onStop() {
				viewHolder.pbProgressBar.setMax(1);
				viewHolder.pbProgressBar.setProgress(0);
			}
		});
	}

	@Override
	public 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)