Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

Learn Android programming with Kotlin: Using VideoView and MediaController

3.00/5 (2 votes)
16 Mar 2020CPOL5 min read 11.5K  
How to use VideoView and MediaController in Kotlin
This post will show you how to play a video clip that is either embedded in the app's resources, or available on the internet by using VideoView and MediaController in Kotlin.

Introduction

Smartphones and tablets are used with many different purposes such as study, entertainment, so on. And watching videos is one of those purposes. So, as Android developers, we must make functions help Android device users to interact with videos easily.

There are many different ways to play a video and control it in an Android app, however, using the VideoView and the MediaController classes can be simplest way.

In this tip, I am going to build a simple app that plays a video clip that is either embedded in the app's resources, or available on the internet by using Kotlin and Android Studio 3.6.1.

Background

VideoView Class

VideoView currently supports the following video formats:

  • H.263
  • H.264 AVC
  • H.265 HEVC
  • MPEG-4 SP
  • VP8
  • VP9

The VideoView class has a wide range of methods that may be called in order to manage the playback of video here. The following methods are used in this article:

  • setVideoUri
  • seekTo
  • start
  • stopPlayback
  • pause
  • setOnPreparedListener
  • setOnCompletionListener
  • getCurrentPosition
  • setMediaController

MediaController Class

The MediaController also provides a set of methods allowing the user to manage the playback of video here. The following method is used in this article:

  • setMediaPlayer

Using the Code

Create the Project and Layout

Create a new Android project and name it MyFirstKotlinApp, choose the Empty activity template, select Kotlin language and leave all other defaults.

In activity_main.xml, delete the existing TextView, and replace it with a VideoView element and two TextView elements with these attributes:

XML
<VideoView
        android:id="@+id/videoview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="4:3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
<TextView
        android:id="@+id/loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="Loading..."
        android:textSize="35sp"
        android:textStyle="bold"
        android:textColor="#a84832"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
<TextView
        android:id="@+id/completed"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="Playback completed"
        android:textSize="25sp"
        android:textStyle="bold"
        android:textColor="#ffff00"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

Playing a Video File using VideoView

To play a video file embedded with the app's resources, first, we must import the video file (can download https://all-free-download.com/free-footage/snowfall_winter_snowflakes_cold_907.html and name it falling_snow.mp4) with the following steps:

  • Right click the res directory in the Project view and select New > Android Resource Directory.

    Image 1

  • Change Resource type to "raw" (Directory name is also changed automatically). Leave all other options as is and click OK.

    Image 2

  • Move (Copy/Cut) the video file (falling_snow.mp4) into (Paste) the raw directory in our project.

    Image 3

To play a video file from the internet, first, in the Android manifest file, add an internet permission to enable the app to access the video file on the internet before the <application> element, at the top level of the manifest:

XML
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.ngocminhtran.myfirstkotlinapp">
    <uses-permission android:name="android.permission.INTERNET" />
    <application...>
        ...   
    </application>
</manifest>

Next, in MainActivity.kt, add a constant for the name of the video file in our app’s resource:

Kotlin
private val VIDEO_NAME = "falling_snow"

or a URL for video file from the interner:

Kotlin
private val VIDEO_NAME = 
"https://images.all-free-download.com/footage_preview/webm/christmas_tree_7.webm"

Also in MainActivity.kt, create a private method called getURI() that tests whether the input string is a URL or a raw resource and return the appropriate URI. This method looks like this:

Kotlin
private fun getURI(videoname:String): Uri{
   if (URLUtil.isValidUrl(videoname)) {
        //  an external URL
        return Uri.parse(videoname);
    } else { //  a raw resource
        return Uri.parse("android.resource://" + getPackageName() +
                "/raw/" + videoname);
    }
}

We also create a new private method called initPlayer() that calls the getURI() and setVideoUri() methods to set the URI that the VideoView will play and start() on the VideoView to start playing:

Kotlin
private fun initPlayer() {
    var videoUri:Uri = getURI(VIDEO_NAME)
    videoview.setVideoURI(videoUri)
    videoview.start()   
}

When we stop the video from playing, we must release all the resources held by the VideoView. To do this, we create a private method called releasePlayer(), and call the stopPlayback() method on the VideoView.

Kotlin
private fun releasePlayer(){
    videoview.stopPlayback()
}

Before building and running our app, we need to override Activity lifecycle methods:

  • onStop() to release the media resources when the app is stopped
  • onStart() to initialize the resources when the app is started again
  • onPause() and add a test for versions of Android older than N (lower than 7.0, API 24). If the app is running on an older version of Android, pause the VideoView here.

The onStop() looks like this:

Kotlin
protected override fun onStop() {
    super.onStop()
    releasePlayer()
}

The onStart():

Kotlin
protected override fun onStart() {
    super.onStart()
    initPlayer()
}

And the onPause():

Kotlin
protected override fun onPause() {
    super.onPause()
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
        videoview.pause()
    }
}

So far, we can build and run our app:

Image 4

We cannot control the media playback such as pause, play, fast-forward, or rewind. These functions will be added in the next step.

Control the Video using MediaController Class

To add a MediaController that controls our video, we must implement the following steps:

  • In onCreate() method, create a new MediaController object and use setMediaPlayer() to connect the object to the VideoView:
    Kotlin
    val controller = MediaController(this)
    controller.setMediaPlayer(videoview)
  • Use setMediaController() to tell the VideoView that the MediaController will be used to control it:
    Kotlin
    videoview.setMediaController(controller)

And now, we can built and run app again. Tapping the VideoView to make the MediaController appear:

Image 5

At the moment, we try to rotate the Android Emulator by clicking the Rotate left button on the Emulator's right bar:

Image 6

The result looks like this:

Image 7

We note that the video restarts from the beginning and here is the behavior that we don’t expect. We can solve this problem by preserving playback position throughout the activity lifecycle with the following steps:

  • In MainActivity.kt, we add a member variable to hold the video's current position (initially 0) and member variable to hold the key for the playback position in the instance state bundle:
    Kotlin
    private val PLAYBACK_TIME = "play_time"
    private var currentPos = 0
  • In initPlayer(), after setVideoUri() but before start(), check to see whether the current position is greater than 0, which indicates that the video was playing at some point. Use the seekTo() method to move the playback position to the current position:
    Kotlin
    private fun initPlayer() {
        var videoUri:Uri = getURI(VIDEO_NAME)
        videoview.setVideoURI(videoUri)
        if (currentPos > 0) {
             videoview.seekTo(currentPos);
        } else {
            videoview.seekTo(1);
        }
        videoview.start()   
    }
  • Override the onSaveInstanceState() method to save the value of current time to the instance state bundle. Get the current playback position with the getCurrentPosition() method:
    Kotlin
    protected override fun onSaveInstanceState(outState: Bundle?) {
        super.onSaveInstanceState(outState)        
         outState?.putInt(PLAYBACK_TIME, videoview.getCurrentPosition())
    }
  • In onCreate(), check for the existence of the instance state bundle, and update the value of current time with the value from that bundle. Add these lines before you create the MediaController:
    Kotlin
    if (savedInstanceState != null) {
        currentPos = savedInstanceState.getInt(PLAYBACK_TIME);
    }

Build and run the app. Try to rotate Emulator again and note how the playback position is saved.

Preparation and Completion Events

The VideoView class defines listeners for several events related to media playback and Listeners for the preparation and completion events are the most common listeners to implement in a media app.

In Java, we must use the onPrepared() and the onCompletion() callbacks for preparation and completion events. In Kotlin, we just implement:

Kotlin
// preparation event
videoview.setOnPreparedListener{  
}
//completion events
videoview.setOnCompletionListener {
}

In our app, we implement the following steps:

  • In InitPlayer(), we change some things as follows:
    Kotlin
    private fun initPlayer() {
        loading.visibility = VideoView.VISIBLE
        completed.visibility = VideoView.INVISIBLE
        var videoUri:Uri = getURI(VIDEO_NAME)
        videoview.setVideoURI(videoUri)
        videoview.setOnPreparedListener{
            loading.visibility = VideoView.INVISIBLE
            if (currentPos > 0) {
                videoview.seekTo(currentPos)
            } else {
                videoview.seekTo(1)
            }
            videoview.start()
        }
        videoview.setOnCompletionListener {
            completed.visibility = VideoView.VISIBLE
            videoview.seekTo(1);
        }
    }

Built and run our app. Each time initPlayer() is called, the loading message should be turned on. It is turned off only when the media is ready to play:

Image 8

When the video finishes playing, the completed message appears:

Image 9

Points of Interest

Using VideoView and MediaController is old title in Android programming and you can easily find a lot of documents about them. However, as a Kotlin beginner, I want to learn how to use these classes in Android programming by using Kotlin from scratch as a way to understand more about Kotlin and how to apply it in Android programming.

History

  • 15th March, 2020: Initial version
  • 16th March, 2020: Second version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)