Android Studio: EXOPlayer の使い方

こちらと同じことを行いました。
[〈kotlin〉ExoPlayer](https://mtnmr.hatenablog.com/entry/2022/09/30/113118)

こちらの記事とも同様です。
[Android Studio: ストリーミング](https://qiita.com/ekzemplaro/items/8d6159c2e988119e7020)

実機の動作確認は、Android 8.1.0 で行いました。

## 環境

インターネットに接続する

```xml:AndroidManifest.xml
（省略）
<uses-permission android:name="android.permission.INTERNET" />
（省略）
```

```app/build.gradle.kts
android {
（省略）
   buildFeatures {
        viewBinding = true
    }
}

（省略）

dependencies {
（省略）
	val mediaVersion = "1.2.0"
    implementation("androidx.media3:media3-exoplayer:$mediaVersion")
    implementation("androidx.media3:media3-ui:$mediaVersion")
    implementation("androidx.media3:media3-exoplayer-dash:$mediaVersion")
}
```

```xml:values/strings.xml
<resources>
    <string name="app_name">exo03</string>
<string name="media_url_mp4">https://storage.googleapis.com/exoplayer-test-media-0/BigBuckBunny_320x180.mp4</string>
</resources>
```

画面

```xml:layout/main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


        <androidx.media3.ui.PlayerView
            android:id="@+id/video_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
```

プログラム

```MainActivity.kt
package org.ekzemplaro

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.media3.common.MediaItem

import androidx.media3.exoplayer.ExoPlayer
import org.ekzemplaro.databinding.ActivityMainBinding


class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    private var player: ExoPlayer? = null

    private var playWhenReady = true //再生・一時停止の状態を保存
    private var currentItem = 0 //メディアアイテムのインデックスを保存
    private var playbackPosition = 0L //再生位置を保存

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }

    override fun onStart() {
        super.onStart()

        initializePlayer()

    }

    override fun onResume() {
        super.onResume()
        hideSystemUi()   //全画面表示にするために他のUIを非表示にする
    }

        private fun hideSystemUi() {
        WindowCompat.setDecorFitsSystemWindows(window, false)
        WindowInsetsControllerCompat(window, binding.videoView).let { controller ->
            controller.hide(WindowInsetsCompat.Type.systemBars())
            controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
        }
    }

    private fun initializePlayer(){
        player = ExoPlayer.Builder(this)
            .build()
            .also { exoPlayer ->
                binding.videoView.player = exoPlayer

                val mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp4))
                exoPlayer.setMediaItem(mediaItem)
                exoPlayer.playWhenReady = playWhenReady
                exoPlayer.seekTo(currentItem, playbackPosition) //特定のアイテムの特定の位置から開始

                exoPlayer.prepare()
            }
    }

    override fun onPause() {
        super.onPause()
    }

        override fun onStop() {
        super.onStop()
            releasePlayer()

    }

    private fun releasePlayer() {
        //playerを破棄する前に情報を保存しておき、中断したところから再開できるようにする。
        player?.let { exoPlayer ->
            playbackPosition = exoPlayer.contentPosition
            currentItem = exoPlayer.currentMediaItemIndex
            playWhenReady = exoPlayer.playWhenReady
            exoPlayer.release()
        }
        player = null
    }
}
```