I have implemented a recyclerview in which i am adding textures views as list items to play videos from url. Now like vine and instagram app i want to play a video when it is visible in the recyclerview and stop/pause video when listitem gets out of screen. Following is my code:
VideosAdapter Class:
public class VideosAdapter extends RecyclerView.Adapter<VideosAdapter.ViewHolder> {
private static String TAG = "VideosAdapter";
Context context;
private ArrayList<String> urls;
RecyclerView recyclerView;
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextureView textureView;
public TextView textView;
public ViewHolder(View v) {
super(v);
textureView = (TextureView) v.findViewById(R.id.textureView);
textView = (TextView) v.findViewById(R.id.textView);
}
}
public VideosAdapter(Context context, RecyclerView recyclerView, final ArrayList<String> urls) {
this.context = context;
this.recyclerView = recyclerView;
this.urls = urls;
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(newState == RecyclerView.SCROLL_STATE_IDLE) {
LinearLayoutManager layoutManager = ((LinearLayoutManager) recyclerView.getLayoutManager());
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition = layoutManager.findFirstCompletelyVisibleItemPosition();
int findLastVisibleItemPosition = layoutManager.findLastVisibleItemPosition();
int findLastCompletelyVisibleItemPosition = layoutManager.findLastCompletelyVisibleItemPosition();
*//*Log.i(TAG, "firstVisiblePosition = " + String.valueOf(firstVisiblePosition));
Log.i(TAG, "findFirstCompletelyVisibleItemPosition = " + String.valueOf(findFirstCompletelyVisibleItemPosition));
Log.i(TAG, "findLastVisibleItemPosition = " + String.valueOf(findLastVisibleItemPosition));
Log.i(TAG, "findLastCompletelyVisibleItemPosition = " + String.valueOf(findLastCompletelyVisibleItemPosition));*//*
Log.i(TAG, "//////////////////////////////////////////////////////////////");
if(findFirstCompletelyVisibleItemPosition>=0) {
Log.i(TAG, "Playing_URl = " + urls.get(findFirstCompletelyVisibleItemPosition));
int tempPreviousUrl = findFirstCompletelyVisibleItemPosition - 1;
if(tempPreviousUrl>=0)
Log.i(TAG, "Stop_Playing_URl = " + urls.get(tempPreviousUrl));
}
else
{
Log.i(TAG, "Playing_URl = " + urls.get(firstVisiblePosition));
int tempPreviousUrl = firstVisiblePosition - 1;
if(tempPreviousUrl>=0)
Log.i(TAG, "Stop_Playing_URl = " + urls.get(tempPreviousUrl));
}
}
}
});
}
// Create new views (invoked by the layout manager)
@Override
public VideosAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_main, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
String url = urls.get(position);
holder.textView.setText(url);
//Log.i("BindViewHolderCalledFor", position + " = " + url);
VideoPlayController videoPlayController = new VideoPlayController(context, recyclerView, holder.textureView, url);
if(position==0) {
videoPlayController.loadVideo();
}
}
@Override
public int getItemCount() {
return urls.size();
}
}
VideoPlayController Class:
public class VideoPlayController implements TextureView.SurfaceTextureListener {
private static String TAG = "VideoPlayController";
Context context;
String url;
MediaPlayer mp;
Surface surface;
SurfaceTexture s;
RecyclerView recyclerView;
TextureView textureView;
public VideoPlayController(Context context, RecyclerView recyclerView, TextureView textureView, final String url) {
this.context = context;
this.recyclerView = recyclerView;
this.textureView = textureView;
this.url = url;
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(newState == RecyclerView.SCROLL_STATE_IDLE) {
Log.i(TAG, "OnScrollStateChangedCalled For: " + url);
//When scroll is at idol position check if item is visible
}
}
});
}
public void loadVideo() {
textureView.setSurfaceTextureListener(this);
}
@Override
public void onSurfaceTextureAvailable(final SurfaceTexture surface, int width, int height) {
Log.d("surface_available-url", this.url);
startVideo(surface);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
Log.d("surface_destroyed-url", this.url);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
Log.d("surface_destroyed-url", this.url);
this.mp.stop();
this.mp.reset();
this.mp.release();
this.mp = null;
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
public void startVideo(SurfaceTexture t)
{
this.surface = new Surface(t);
this.mp = new MediaPlayer();
this.mp.setSurface(this.surface);
try {
Uri uri = Uri.parse(this.url);
this.mp.setDataSource(url);
this.mp.prepareAsync();
this.mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mp.setLooping(true);
mp.start();
}
});
} catch (IllegalArgumentException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
} catch (IllegalStateException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
try {
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
public void changePlayState()
{
if(this.mp.isPlaying())
this.mp.stop();
else
this.mp.start();
}
public static boolean isViewVisible(View subView, View parentView) {
Rect scrollBounds = new Rect();
parentView.getHitRect(scrollBounds);
if (subView.getLocalVisibleRect(scrollBounds)) {
return true;
}
return false;
}
}
To achieve this thing i get visible items positions as discussed in this thread. But i dont know how to pass the visible scroll position to my VideoPlayController class and how to track and access the right object based on scroll position.
I know this is late but many people are still looking for a way to do this.
You can use VideoPlayerManager project, to achieve this functionality