Kohii 201 - Videos in RecyclerView

28 June 2020
#Android#AndroidX#Kohii#ExoPlayer#RecyclerView#ExoPlayer in RecyclerView

Videos in RecyclerView

This tutorial shows you how to use Kohii to enable Video playback in a RecyclerView, including automatic start/pause playbacks, recycling playback resources to reduce the memory usage and improve the performance.

Source code

Source code: kohii-tutorial-201

Objective

The Application we are about to build will:

  • Have a RecyclerView with many videos
  • The first video from top which is visible at least 65% will start playing automatically. Otherwise, it will pause automatically.
  • Reuse a few PlayerView instances for different videos

Requirement

It is suggested to finish the previous tutorial first. Also you need to be familiar with the RecyclerView at basic level.

Hands-on

We will start with what has been done after the step 1 of this tutorial.

kohii-tutorial-201/tree/step-0

Step 1: Adding RecyclerView

We will need to add RecyclerView dependency, and use it in our layout file. This step has nothing to do with Kohii yet, but a important starting step. You can find the change here: kohii-tutorial-201/tree/step-1

Step 2: Adding data definition and more RecyclerView implementations

In this step, we add more details about the implementation. In reality, you will have your own data source with many different videos. In this step, we will just reuse a video file for all data items. Also to make it close to real life scenario, I will use the AndroidX Lifecycle library in the code:

Source code

Below is our App after the step 2: kohii-tutorial-201/tree/step-2

Step 3: Binding the Video using Kohii

In this step, we will use Kohii to setup our videos so that each will be automatically played properly. By default, from top to bottom, the first video that is at least 65% visible will start playing.

The changes is gathered in this commit. To explain this step: we want to bind the ViewHolder's PlayerView using Kohii, so first we need to pass a Kohii instance down to the Adapter:

class MainAdapter(
  private val kohii: Kohii,
  diffCallback: ItemCallback<VideoItem>
)

Then in onBindViewHolder, we bind the video:

override fun onBindViewHolder(holder: VideoViewHolder, position: Int) {
  val videoItem = getItem(position) ?: return
  kohii.setUp(videoItem.videoUrl) {
    tag = "${videoItem.videoUrl}+${position}"
  }.bind(holder.playerView)
}

Note that, as learned from the previous tutorial, we want the video playback state to be saved, so we will also set a tag for it. For your information, by setting a unique tag, Kohii will also save the playback state when it is paused. Which means that, if user scrolls the video off-screen, its last playback position will be saved, and when user scrolls the video back, it will start playing from that saved position. Without a unique tag, it will start playing from the beginning.

After this step, our App will look like this →

Now this is our code after step 3: kohii-tutorial-201/tree/step-3

Short break

So with a few steps, we have a RecyclerView with many videos, each will start play automatically when it is visible enough. By default, 65% means visible enough, but you are freely change this threshold using the setup options like below:

kohii.setUp(videoItem.videoUrl) {
  tag = "${videoItem.videoUrl}+${position}"
  threshold = 0.5F
}.bind(holder.playerView)

With the setting above, your video will be able to play when it is at least 50% visible.

In this tutorial, we do not go deeper in the available options, but we want to focus on major feature that may benefit your app more. In next steps, we will learn how to reuse a few PlayerView instances for all of your videos.

Step 4: Recycling PlayerView instances

Considering the binding below:

kohii.setUp(videoItem.videoUrl) {
  tag = "${videoItem.videoUrl}+${position}"
}.bind(holder.playerView)

The holder.playerView is a PlayerView instance. Kohii supports a recycling mechanism by which if you bind to a ViewGroup instead of a PlayerView (we call the ViewGroup a container), Kohii will acquire a PlayerView (we call it renderer) and add it to that container automatically and properly. When that PlayerView is not used anymore, Kohii will release it.

How it works: Kohii acquires renderer instance from a RendererProvider. The RendererProvider has the responsibility to return a renderer instance when requested. The default implementation of the RendererProvider has the ability to recycle the renderer instance so that, when Kohii releases the renderer, it sanitizes the renderer instance and save it to cache; and when Kohii acquires the renderer, it will return a cached instance if available, or create a new one. Kohii uses a default implementation to create and sanitize the renderer instances, but the RendererProvider is completely configurable. We will discuss this in another discussion.

To recycle PlayerView instances in our App, we need to:

  • Replace the PlayerView in our layout with a ViewGroup to contain the renderer. A FrameLayout would be enough in our case:
app/src/main/res/layout/holder_video_item.xml

-  <com.google.android.exoplayer2.ui.PlayerView
-      android:id="@+id/playerView"
+  <FrameLayout
+      android:id="@+id/playerViewContainer"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintTop_toTopOf="parent"
  • Change the instance type of the PlayerView to FrameLayout in our ViewHolder:
app/src/main/java/kohii/tut/c201/VideoViewHolder.kt

 class VideoViewHolder(itemView: View) : ViewHolder(itemView) {
 
-  val playerView: PlayerView = itemView.findViewById(R.id.playerView)
+  val playerView: FrameLayout = itemView.findViewById(R.id.playerViewContainer)
 }

We don't need to change the binding, because Kohii automatically recognizes the difference and will apply the recycling mechanism accordingly. In the video below, you can see that as user scrolls, the next video will reuse the same PlayerView instance:

Note: It is important to note that, the ViewGroup you use to contain the PlayerView must be empty, i.e. it must not be used to contain any other Views. Kohii will automatically remove all other Views before placing the PlayerView into it.

Here is our project after step 4: kohii-tutorial-201/tree/step-4

Wrap up

In this tutorial, I have introduced the way to use Kohii to create a simple video list using RecyclerView that also reuses one PlayerView instance for many videos in just a few steps. The real-life scenario may have many more features like manual playback controller, open full-screen player and back, etc. You can build most of that features using Kohii, but we will not cover all of them in tutorials. The Kohii library comes with a feature-rich demo application that you can get many ideas from: eneim/kohii

And with the extensible characteristic, you can also build much more from the core of Kohii.

There is also information about Kohii here and here. Feel free to check them out and give feedback.

Last but not least

Kohii is an open source project I build after work. It has been under development for nearly 2 years and I'm improving it everyday. If you are using Kohii and finding it useful for your work, you can send me some help either by staring the repository or/and buying me a cup of coffee at my sponsor page. Your help is always appreciated.

Thanks for using Kohii and happy coding.