当前位置: 首页 > news >正文

Compose笔记(十六)--ExoPlayer

        这一节了解一下Compose中的ExoPlayer的使用,我们在开发Android应用时,经常会使用到播放器,这个ExoPlayer框架就相对成熟,易上手,现简单总结如下:

1. ExoPlayer 核心类
       ExoPlayer 是 ExoPlayer库的核心类,负责管理媒体播放的整个生命周期,包括加载、播放、暂停、停止等操作。
       作用:1 创建播放器实例。2 管理播放状态(播放、暂停、停止)。3 控制播放进度(如跳转到指定位置)。4 监听播放事件(如播放完成、错误等)。
2. SimpleExoPlayer
      SimpleExoPlayer 是 ExoPlayer 的一个简化实现,适用于大多数基本播放场景。
      作用:1 提供了更简单的 API 来管理播放。2 支持音频和视频播放。3 通常用于不需要复杂自定义的场景。
3. Player.Listener
      含义:Player.Listener 是 ExoPlayer 的监听器接口,用于接收播放状态变化和事件通知。
      作用:1 监听播放状态变化(如播放、暂停、停止)。2 监听播放进度变化。3 监听错误事件。4 监听媒体加载状态(如缓冲完成)。
4. MediaItem
      含义:MediaItem 表示要播放的媒体资源,可以是本地文件或网络资源。
      作用:1 定义媒体资源的 URI(如本地路径或网络 URL)。2 设置媒体元数据(如标题、描述等)。3添加到播放列表中。
5. PlayerView
      含义:PlayerView 是 ExoPlayer 提供的 UI 组件,用于显示视频画面和控制播放。
     作用:1 显示视频画面。2 提供内置的播放控制按钮(播放、暂停、进度条等)。3 可以通过Compose的AndroidView或ComposeView集成到ComposeUI中。
6. 播放控制方法
play():开始播放。
pause():暂停播放。
stop():停止播放并重置播放器状态。
seekTo(position: Long):跳转到指定位置(以毫秒为单位)。
setPlayWhenReady(playWhenReady: Boolean):设置播放器是否准备好时自动播放。
7. 播放状态
ExoPlayer 提供了多种播放状态,可以通过 Player.State 或 playbackState 属性获取:
STATE_IDLE:播放器空闲状态,未准备播放。
STATE_BUFFERING:播放器正在缓冲数据。
STATE_READY:播放器已准备好,可以播放。
STATE_ENDED:播放结束。
8. 事件监听(如播放完成)
含义:通过监听器可以捕获播放完成事件。

栗子

app模块下gradle:implementation ("com.google.android.exoplayer:exoplayer-core:2.19.1")
implementation ("com.google.android.exoplayer:exoplayer-hls:2.19.1")
implementation ("com.google.android.exoplayer:exoplayer-ui:2.19.1")
implementation("androidx.preference:preference-ktx:1.2.1")
<activityandroid:name=".testexoplayer.YourVideoActivity"android:exported="true"android:theme="@style/Theme.ComposeNavigationDemo"android:supportsPictureInPicture="true"android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity>
package com.example.composenavigationdemo.testexoplayerimport android.content.Context
import android.content.pm.ActivityInfo
import android.os.Bundle
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.ui.StyledPlayerView
import androidx.preference.PreferenceManagerclass YourVideoActivity : ComponentActivity() {private lateinit var exoPlayer: ExoPlayerprivate val PREF_KEY_PLAYBACK_POSITION = "playback_position"override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {VideoPlayerScreen()}}@Composablefun VideoPlayerScreen() {val videoUrl = "https://vdept3.bdstatic.com/mda-rbq74um403w6qq1c/cae_h264/1740460540715545764/mda-rbq74um403w6qq1c.mp4?v_from_s=hkapp-haokan-suzhou&auth_key=1743250028-0-0-dbffc551f0aea2bffc89d537dba36202&bcevod_channel=searchbox_feed&cr=0&cd=0&pd=1&pt=3&logid=0428327789&vid=10916160709390273754&klogid=0428327789&abtest=\n" var isPlaying by remember { mutableStateOf(true) }val context = LocalContext.currentval playerView = remember {StyledPlayerView(this).apply {layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)}}val player = remember {ExoPlayer.Builder(this).build().apply {setMediaItem(MediaItem.fromUri(videoUrl))// 读取播放进度val playbackPosition = getPlaybackPosition(context)if (playbackPosition > 0) {seekTo(playbackPosition)}prepare()playWhenReady = isPlaying}}DisposableEffect(Unit) {playerView.player = playeronDispose {// 保存播放进度savePlaybackPosition(context, player.currentPosition)player.release()}}Box(modifier = Modifier.fillMaxSize()) {AndroidView(factory = { playerView },modifier = Modifier.fillMaxSize())Button(onClick = {if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {enterPictureInPictureMode()}},modifier = Modifier.align(androidx.compose.ui.Alignment.BottomEnd)) {Text(text = "进入画中画")}}}private fun savePlaybackPosition(context: Context, position: Long) {val prefs = PreferenceManager.getDefaultSharedPreferences(context)prefs.edit().putLong(PREF_KEY_PLAYBACK_POSITION, position).apply()}private fun getPlaybackPosition(context: Context): Long {val prefs = PreferenceManager.getDefaultSharedPreferences(context)return prefs.getLong(PREF_KEY_PLAYBACK_POSITION, 0)}override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean,newConfig: android.content.res.Configuration) {super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)if (isInPictureInPictureMode) {// 进入画中画模式requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE} else {// 退出画中画模式
//            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIEDrequestedOrientation = ActivityInfo.SCREEN_O RIENTATION_SENSOR_PORTRAIT}}
}

分析:上面实现了一个画中画的播放效果。

注意:

1. 依赖管理与版本选择
版本兼容性:ExoPlayer 的版本需要与项目的 Android Gradle 插件版本和 Compose 版本兼容,避免因版本不匹配导致的问题
2. 生命周期管理
释放资源:ExoPlayer是资源密集型组件,必须在不再使用时释放资源。可以通过DisposableEffect或onDispose 来管理生命周期,确保在onStop或onDestroy时调用player.release()。

DisposableEffect(lifecycleOwner) {onDispose {exoPlayer.release()}
}

3. 媒体源设置
动态设置媒体源:在播放不同媒体时,需要动态设置 MediaItem,并调用 player.setMediaItem() 和 player.prepare()。

4. 线程与异步操作
后台线程加载:避免在主线程中进行媒体加载或解码操作,ExoPlayer会自动处理大部分异步操作,但确保网络请求或大数据处理在后台线程中完成。
异步准备:如果需要预加载媒体,可以在后台线程中调用 player.prepare(),避免阻塞UI。


http://www.mrgr.cn/news/98187.html

相关文章:

  • 数据结构day05
  • Git版本管理系列:(三)远程仓库
  • OpenHarmony5.0.2 音频audio适配
  • 网络机顶盒怎么连接WiFi-机顶盒连接wifi攻略,乐看家桌面轻松畅享网络视听
  • C++初阶-inline的使用
  • 09-设计模式企业场景 面试题-mk
  • PHM学习软件|PHM预测性维护系统
  • 『Kubernetes(K8S) 入门进阶实战』实战入门 - Pod 详解
  • 深入理解 RxSwift 中的 Driver:用法与实践
  • Ubuntu 22.04 AI大模型环境配置及常用工具安装
  • 单片机实现多线程的方法汇总
  • dify windos,linux下载安装部署,提供百度云盘地址
  • 快速上手Linux联网管理
  • 库学习04——numpy
  • 【笔记ing】AI大模型-02开发环境搭建
  • 【论文阅读】RMA: Rapid Motor Adaptation for Legged Robots
  • 【微服务】SpringBoot 整合 Lock4j 分布式锁使用详解
  • 大模型开发:源码分析 Qwen 2.5-VL 视频抽帧模块(附加FFmpeg 性能对比测试)
  • 算法题(123):回文日期
  • yarn:error Error: certificate has expiredERR_OSSL_EVP_UNSUPPORTED解决