Reputation: 1379
I am working on a project which should include a list of videos from allover the internet (video sources are different - youtube, vimeo, facebook, videos hosted on servers, ...). I am trying to make a ListView, where item has a video player and some description When user clicks on play button the video starts playing. I made one example, where I use VideoView as player, but soon realised that the performance is not very good - scrolling is very laggy.
All of this is located in a RecyclerView and everything is handled by RecyclerViewAdapter.
I am wondering if someone has any experience with this and what is the best practice.
EDIT
My code
public class ListFragment extends Fragment {
ArrayList<Video> videoList;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
RecyclerView rv = (RecyclerView) inflater.inflate(
R.layout.fragment_cheese_list, container, false);
videoList = SplashActivity.videoList;
setupRecyclerView(rv);
return rv;
}
private void setupRecyclerView(RecyclerView recyclerView) {
recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
recyclerView.setAdapter(new SimpleStringRecyclerViewAdapter(getActivity(), videoList));
}
public class SimpleStringRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> {
private final TypedValue mTypedValue = new TypedValue();
private int mBackground;
private ArrayList<Video> mVideoList;
public class ViewHolder extends RecyclerView.ViewHolder {
public String mBoundString;
public final View mView;
public final VideoView mVideoView;
public final TextView mTextView;
public final TextView mCountTextView;
public final TextView mHintTextView;
public final Button mPlayButton;
public final ImageView mFavoriteIcon;
public final RelativeLayout mRelativeLayout;
public final ProgressBar mProgressBar;
public ViewHolder(View view) {
super(view);
mView = view;
mVideoView = (VideoView) view.findViewById(R.id.listVideoView);
mTextView = (TextView) view.findViewById(R.id.gifTitleTextView);
mCountTextView = (TextView) view.findViewById(R.id.countTextView);
mHintTextView = (TextView) view.findViewById(R.id.hintTextView);
mPlayButton = (Button) view.findViewById(R.id.playButton);
mFavoriteIcon = (ImageView) view.findViewById(R.id.favoriteImageView);
mRelativeLayout = (RelativeLayout) view.findViewById(R.id.relativeLayout);
mProgressBar = (ProgressBar) view.findViewById(R.id.progressBar);
}
@Override
public String toString() {
return super.toString() + " '" + mTextView.getText();
}
}
public SimpleStringRecyclerViewAdapter(Context context, ArrayList<Video> videoList) {
context.getTheme().resolveAttribute(R.attr.selectableItemBackground, mTypedValue, true);
mVideoList = videoList;
mBackground = mTypedValue.resourceId;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
view.setBackgroundResource(mBackground);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final Video tempVideo = mVideoList.get(position);
holder.mBoundString = tempVideo.getGifTitle();
holder.mTextView.setText(tempVideo.getGifTitle());
float count = tempVideo.getCount();
String countText = "";
if (count >= 1000)
countText = String.format("%.1f", count / 1000) + "k";
else
countText = String.format("%d", (int)count);
holder.mCountTextView.setText(countText);
holder.mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.mVideoView.start();
}
});
holder.mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// This is just to show image when loaded
mp.start();
mp.pause();
}
});
holder.mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// setLooping(true) didn't work, thats why this workaround
holder.mVideoView.setVideoPath(tempVideo.getGifUrl());
holder.mVideoView.start();
}
});
holder.mVideoView.setVideoPath(tempVideo.getGifUrl());
}
@Override
public int getItemCount() {
return videoList.size();
}
}
}
App looks like this:
Upvotes: 4
Views: 16061
Reputation: 3346
I think VideoView is calling prapare method automatically whenever new row is drawn. So each time you scroll, video starts and pauses. Trick you have done to show thumbnail is not practical. It may hugely effect performance. Try to avoid and check how performance changes. Also you can control your CPU usage from bottom layout of Android Studio.
holder.mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.mVideoView.start();
}
});
holder.mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// This is just to show image when loaded
mp.start();
mp.pause();
}
});
holder.mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// setLooping(true) didn't work, thats why this workaround
holder.mVideoView.setVideoPath(tempVideo.getGifUrl());
holder.mVideoView.start();
}
});
Also following lines are need to called once. Otherwise, as you wrote them inside onBindView each time you scroll new listeners are created and it costs to memory.
We need to verify if problem is true or not. You can try to add a log to onPrepare method body and check the results.
I am waiting for response.
Good luck there.
Upvotes: 2