ZassX
ZassX

Reputation: 1379

Android ListView list of videos

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:

enter image description here

Upvotes: 4

Views: 16061

Answers (1)

Emre Akt&#252;rk
Emre Akt&#252;rk

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

Related Questions