0Pricing
Android Academy · Урок

Воспроизведение аудио и видео

Простое воспроизведение мультимедиа в Android

«Воспроизведение аудио и видео» — бесплатный урок Android Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Android Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Android Academy содержит 4 уроков всего.

За пределами изображений: воспроизведение медиа

Coil прекрасно отображает изображения, но приложения также воспроизводят звук и видео: сигнал уведомления, подкаст, фоновый ролик или ленту видео. В Android для работы с медиа предусмотрены специализированные API.

Современная рекомендуемая библиотека — Media3 (ExoPlayer). Она значительно лучше старого MediaPlayer справляется с потоковой передачей, форматами, буферизацией и управлением воспроизведением. В этом уроке вы научитесь воспроизводить простое аудио и видео в приложении Compose.

Добавление зависимостей Media3

Media3 разделена на модули. Для большинства приложений нужны media3-exoplayer (механизм воспроизведения) и media3-ui (готовые представления проигрывателя). Для видео в Compose также можно использовать PlayerView через AndroidView.

// build.gradle.kts (module level)
dependencies {
    implementation("androidx.media3:media3-exoplayer:1.5.0")
    implementation("androidx.media3:media3-ui:1.5.0")
}

Создание ExoPlayer

ExoPlayer создаётся на основе Context. Ему передаётся MediaItem (URL или локальный файл), затем вызывается prepare() и запускается воспроизведение. Проигрыватель работает в собственных потоках, поэтому интерфейс не блокируется.

Важно: проигрыватель использует системные ресурсы, поэтому его нужно освободить. Подробнее об этом — далее.

import android.content.Context
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer

fun createPlayer(context: Context, url: String): ExoPlayer {
    val player = ExoPlayer.Builder(context).build()
    player.setMediaItem(MediaItem.fromUri(url))
    player.prepare()
    player.playWhenReady = true
    return player
}

Воспроизведение аудио

Для воспроизведения только аудио настройка такая же: достаточно указать в MediaItem URL аудиофайла (mp3, aac и т. д.). Представление для отображения не требуется, поэтому управление выполняется через объект проигрывателя: play(), pause(), seekTo().

Этого достаточно, чтобы создать проигрыватель подкастов или музыки.

import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer

fun playPodcast(player: ExoPlayer, audioUrl: String) {
    player.setMediaItem(MediaItem.fromUri(audioUrl))
    player.prepare()
    player.play()
}

fun togglePause(player: ExoPlayer) {
    if (player.isPlaying) player.pause() else player.play()
}

Сохранение проигрывателя в Compose

В Compose следует создать проигрыватель один раз и сохранять его между рекомпозициями. Используйте remember, чтобы новый проигрыватель не создавался при каждой рекомпозиции.

Сочетайте это с правильной очисткой ресурсов (в следующем эпизоде), чтобы не допустить утечек.

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer

@Composable
fun rememberPlayer(url: String): ExoPlayer {
    val context = LocalContext.current
    return remember {
        ExoPlayer.Builder(context).build().apply {
            setMediaItem(MediaItem.fromUri(url))
            prepare()
        }
    }
}

Освобождение проигрывателя

Проигрыватель удерживает кодеки, буферы и аудиофокус. Если забыть освободить его, произойдёт утечка памяти, а воспроизведение может продолжиться после закрытия экрана. В Compose DisposableEffect выполняет очистку, когда компонуемый элемент покидает композицию.

Всегда вызывайте там player.release().

import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.media3.exoplayer.ExoPlayer

@Composable
fun ManagedPlayer(player: ExoPlayer) {
    DisposableEffect(player) {
        onDispose {
            player.release()
        }
    }
    // ... use player here
}

Отображение видео с помощью PlayerView

Media3 предоставляет готовый PlayerView с элементами управления. В Compose нет встроенного компонуемого элемента для видео, поэтому представление встраивается с помощью AndroidView, после чего к нему подключается проигрыватель.

Так вы сразу получаете кнопки воспроизведения и паузы, шкалу перемотки и полноэкранный режим.

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView

@Composable
fun VideoPlayer(player: ExoPlayer, modifier: Modifier = Modifier) {
    AndroidView(
        factory = { context ->
            PlayerView(context).apply {
                this.player = player
            }
        },
        modifier = modifier
    )
}

Полный экран видео

Объединим всё вместе: создадим проигрыватель, сохраним его, подключим к PlayerView и освободим при уничтожении. Это автономный экран видео, который можно повторно использовать.

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView

@Composable
fun VideoScreen(videoUrl: String) {
    val context = LocalContext.current
    val player = remember {
        ExoPlayer.Builder(context).build().apply {
            setMediaItem(MediaItem.fromUri(videoUrl))
            prepare()
            playWhenReady = true
        }
    }
    DisposableEffect(Unit) { onDispose { player.release() } }

    AndroidView(
        factory = { PlayerView(it).apply { this.player = player } },
        modifier = Modifier.fillMaxWidth().height(220.dp)
    )
}

Отслеживание состояния воспроизведения

Чтобы обновлять интерфейс (значок воспроизведения или паузы, индикатор выполнения), отслеживайте проигрыватель с помощью Player.Listener. Он сообщает об изменениях состояния, например о буферизации, готовности и завершении, а также о том, активно ли воспроизведение.

Добавляйте слушатель при появлении экрана и удаляйте его при очистке.

import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer

fun observe(player: ExoPlayer, onPlaying: (Boolean) -> Unit): Player.Listener {
    val listener = object : Player.Listener {
        override fun onIsPlayingChanged(isPlaying: Boolean) {
            onPlaying(isPlaying)
        }
        override fun onPlaybackStateChanged(state: Int) {
            when (state) {
                Player.STATE_BUFFERING -> { /* show spinner */ }
                Player.STATE_READY -> { /* ready */ }
                Player.STATE_ENDED -> { /* finished */ }
            }
        }
    }
    player.addListener(listener)
    return listener
}

Пауза при переходе приложения в фон

Для встроенного видео (не в музыкальном приложении) обычно нужно приостанавливать воспроизведение, когда пользователь покидает экран, и возобновлять его при возвращении. Можно связать воспроизведение с жизненным циклом Compose: наблюдать за Lifecycle и ставить воспроизведение на паузу при ON_PAUSE.

Это предотвращает воспроизведение видео, которое пользователь не видит, и экономит заряд батареи.

import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.media3.exoplayer.ExoPlayer

@Composable
fun PauseWithLifecycle(player: ExoPlayer) {
    val lifecycleOwner = LocalLifecycleOwner.current
    DisposableEffect(lifecycleOwner) {
        val observer = LifecycleEventObserver { _, event ->
            when (event) {
                Lifecycle.Event.ON_PAUSE -> player.pause()
                Lifecycle.Event.ON_RESUME -> player.play()
                else -> {}
            }
        }
        lifecycleOwner.lifecycle.addObserver(observer)
        onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
    }
}

Фоновое аудио с MediaSession

Если аудио должно продолжать воспроизводиться в фоне (музыка, подкасты), оберните воспроизведение в MediaSessionService. Это обеспечивает интеграцию с системными элементами управления, экраном блокировки и кнопками Bluetooth.

Решение сложнее, но основная идея заключается в предоставлении доступа к проигрывателю через MediaSession.

import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService

class PlaybackService : MediaSessionService() {
    private var session: MediaSession? = null

    override fun onCreate() {
        super.onCreate()
        val player = ExoPlayer.Builder(this).build()
        session = MediaSession.Builder(this, player).build()
    }

    override fun onGetSession(controllerInfo: MediaSession.ControllerInfo) = session

    override fun onDestroy() {
        session?.run { player.release(); release() }
        session = null
        super.onDestroy()
    }
}

Быстрая проверка

На экране Compose, где хранится ExoPlayer, какой API Compose следует использовать, чтобы освободить проигрыватель, когда экран покидает композицию?

Итоги

Вы добавили воспроизведение аудио и видео:

  • Используйте Media3 ExoPlayer — современную замену MediaPlayer.
  • Создайте проигрыватель, задайте MediaItem, вызовите prepare(), а затем play().
  • В Compose сохраняйте проигрыватель с помощью remember и освобождайте его в onDispose внутри DisposableEffect.
  • Отображайте видео, встраивая PlayerView с помощью AndroidView.
  • Отслеживайте состояние через Player.Listener, а для фонового аудио используйте MediaSessionService.

На этом завершается курс «Загрузка изображений и медиа с Coil». Теперь вы умеете плавно загружать изображения и воспроизводить медиа современным способом Android.

Часто задаваемые вопросы

Урок «Воспроизведение аудио и видео» бесплатный?

Да — полный текст урока «Воспроизведение аудио и видео» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Android Academy, подпишись на CoddyKit PRO. Курс Android Academy содержит 4 уроков всего.

Чему я научусь в уроке «Воспроизведение аудио и видео»?

Простое воспроизведение мультимедиа в Android Ты практикуешь Android Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Android Academy?

Предыдущий опыт не требуется. Android Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Воспроизведение аудио и видео»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Android Academy?

Да. Каждый урок Android Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Загрузка изображений с Coil
  2. Заполнители и состояния ошибок
  3. Кэширование и производительность
  4. Воспроизведение аудио и видео
← Назад к Android Academy