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。
相关文章:
Compose笔记(十六)--ExoPlayer
这一节了解一下Compose中的ExoPlayer的使用,我们在开发Android应用时,经常会使用到播放器,这个ExoPlayer框架就相对成熟,易上手,现简单总结如下: 1. ExoPlayer 核心类 ExoPlayer 是 ExoPlayer库的核心类&#…...
如何使用AI辅助开发R语言
R语言是一种用于统计计算和图形生成的编程语言和软件环境,很多学术研究和数据分析的科学家和统计学家更青睐于它。但对与没有编程基础的初学者而言,R语言也是有一定使用难度的。不过现在有了通义灵码辅助编写R语言代码,我们完全可以用自然语言…...
Git版本管理系列:(三)远程仓库
目录 与远程仓库平台(github\gitee等)建立连接本地仓库关联远程仓库本地仓库内容推送远程仓库:PUSH将远程仓库的更新拉取到本地:PULL语法总结 与远程仓库平台(github\gitee等)建立连接 远程仓库平台相当于一个网盘,我们可以把自己的代码上传上去。就像网…...
React Hooks: useRef,useCallback,useMemo用法详解
1. useRef(保存引用值) useRef 通常用于保存“不会参与 UI 渲染,但生命周期要长”的对象引用,比如获取 DOM、保存定时器 ID、WebSocket等。 新建useRef.js组件,写入代码: import React, { useRef, useSt…...
STM32F103复用JTAG/SWD引脚为GPIO
普中-精灵1开发板,主芯片为STM32F103C8T6,4个独立按键K1~K4依次接PA15~PA12,按下为低电平,8个LED灯D1~D8,依次接PA0~PA7。查询手册得知:PA15主功能为JTDI,PA14为JTCK/SWCLK,PA13为JT…...
[wifi SAE]wpa3-personal
SAE :Simultaneous Authentication of Equals(同等同时认证) wpa2和wpa3之间最大的区别是认证过程的区别 WPA2不安全性 1.sta和ap预置psk(AP密码) 2.四次握手生成ptk用于后续数据加密的密钥 ptk计算基于psk、双方随机数; 双方都产…...
电路方案分析(二十)TPS63xxx系列DC/DC电源EMI PCB设计方案
tips:资料来自网络,仅供学习使用。[TOC](TPS63xxx系列DC/DC电源EMI PCB设计方案) 1.概述 通过TPS63xxx系列DC/DC电源模块来分析降低直流/直流降压/升压转换器辐射 EMI 的来源以及相关PCB设计。 下面都以最常用的TPS63070为例说明: 典型应用…...
DeepSeek 在金融领域的应用解决方案
DeepSeek 在金融领域的应用解决方案 一、背景 随着人工智能技术的快速发展,DeepSeek 作为一款国产大模型,凭借其强大的语义理解、逻辑推理和多模态处理能力,在金融行业迅速崭露头角。金融行业作为经济的核心,面临着激烈的市场竞…...
Java 大厂面试题 -- JVM 深度剖析:解锁大厂 Offe 的核心密钥
最近佳作推荐: Java大厂面试高频考点|分布式系统JVM优化实战全解析(附真题)(New) Java大厂面试题 – JVM 优化进阶之路:从原理到实战的深度剖析(2)(New&#…...
【AI提示词】API开发专家
提示说明 API开发专家专注于设计和实现高效、稳定、安全的应用程序接口(API)。他们通过深入理解业务需求和用户场景,为用户提供定制化的API解决方案。 提示词 # 角色 API开发专家## 注意 1. 专家设计应考虑API开发过程中的技术细节和用户需…...
目标追踪Hyperspectral Adapter for Object Tracking based on Hyperspectral Video
论文作者:Long Gao,Yunhe Zhang,Langkun Chen,Yan Jiang,Weiying Xie,Yunsong Li 作者单位:Xidian University;the University of Sheffield 论文链接:http://arxiv.org/abs/2503.22199v1 内容简介: 1)方向&#x…...
深度剖析SSD多段L2P表查找加速技术
在固态硬盘(SSD)控制器中,逻辑块地址(LBA)需要通过映射表(L2P Table)映射到NAND闪存的物理地址(PA)。随着SSD容量的增长,L2P表的大小也随之增加,这给查找操作带来了性能挑战。 在SSD控制器中,LBA需借助L2P表映射为NAND物理地址。映射表最小规模为 (O(n * \lg (n)))…...
【MQTT-协议原理】
MQTT-协议原理 ■ MQTT-协议原理■ MQTT-服务器 称为"消息代理"(Broker)■ MQTT协议中的订阅、主题、会话■ 一、订阅(Subscription)■ 二、会话(Session)■ 三、主题名(Topic Name&a…...
PCIe 5.0光学SSD原型问世!
近日,Kioxia Corporation(铠侠)、AIO Core Co., Ltd. 和 Kyocera Corporation(京瓷)联合宣布成功开发了一款支持 PCIe 5.0 接口的光学 SSD 原型。该技术旨在通过光接口替换传统的电接口,从而显著增加计算设…...
Raymarching Textures In Depth
本节课最主要的就是学会hlsl中使用纹理采样 float4 color Texture2DSample(Texobj, TexobjSampler, uv); return color; 课程中的代码(没有这张图我就没做) 课程代码产生深度的原因是uv偏移,黑色区域会不断向左偏移,直到找到白色…...
maven编译jar踩坑[sqlite.db]
背景: 最近在项目中搞多数据源切换的job,在src/resource下有初始化的sqlite默认文件供后续拷贝使用,在测试阶段没有什么问题,但是一部署到服务器上运行就有问题。 报错现象: 找不到这个sqlite.db文件或者文件格式有问题&#x…...
文献总结:ECCV2022-BEVFormer
BEVFormer 一、文章基本信息二、文章背景三、BEVFormer架构(1) BEV 查询(2) 空间交叉注意力机制(3) 时间自注意力机制(4) BEV应用(5) 实施细节 四、实验五、总结 一、文章基本信息 标题BEVFormer: Learning Bird’s-Eye-view Representation from Multi-camera images via spa…...
Openlayers:海量图形渲染之WebGL渲染
最近由于在工作中涉及到了海量图形渲染的问题,因此我开始研究相关的解决方案。我在网络上寻找相关的解决方案时发现许多的文章都提到利用Openlayers中的WebGLPointsLayer类,可以实现渲染海量的点,之后我又了解到利用WebGLVectorLayer类可以渲…...
RCE漏洞学习
1,What is RCE? 在CTF(Capture The Flag)竞赛中,RCE漏洞指的是远程代码执行漏洞(Remote Code Execution)。这类漏洞允许攻击者通过某种方式在目标系统上执行任意代码,从而完全控制目…...
如何将网页保存为pdf
要将网页保存为PDF,可以按照以下几种方法操作: 1. 使用浏览器的打印功能 大多数现代浏览器(如Chrome、Firefox、Edge等)都支持将网页保存为PDF文件。步骤如下: 在 Google Chrome 中: 打开你想保存为PDF…...
什么是继承?js中有哪儿些继承?
1、什么是继承? 继承是面向对象软件技术中的一个概念。 2、js中有哪儿些继承? js中的继承有ES6的类class的继承、原型链继承、构造函数继承、组合继承、寄生组合继承。 2.1 ES6中类的继承 class Parent {constructor() {this.age 18;} }class Chil…...
如何使用 Grafana 连接 Easyearch
Grafana 介绍 Grafana 是一款开源的跨平台数据可视化与监控分析工具,专为时序数据(如服务器性能指标、应用程序日志、业务数据等)设计。它通过直观的仪表盘(Dashboards)帮助用户实时监控系统状态、分析趋势࿰…...
mindsdb AI 开源的查询引擎 - 用于构建 AI 的平台,该平台可以学习和回答大规模联合数据的问题。
一、软件介绍 文末提供源码和程序下载学习 MindsDB 是一种解决方案,使人类、AI、代理和应用程序能够以自然语言和 SQL 查询数据,并在不同的数据源和类型中获得高度准确的答案。此开源程序是一个联合查询引擎,可以整理您的数据蔓延混乱&#…...
802.11a ofdm 过程了解
ofdm_demo.py import numpy as np from scipy import interpolate import commpy as cpy import ofdm_debug as ofdm_debug class OFDMSystem:def __init__(self, K64, CPNone, P8, pilotValue33j, Modulation_typeQAM16, channel_typerandom, SNRdb25,debugFalse):# 设置OFDM…...
BOTA六维力矩传感器如何打通机器人AI力控操作的三层架构?感知-决策-执行全链路揭秘
想象一下,你对着一个机器人说:“请帮我泡杯茶。”然后,它就真的开始行动了:找茶壶、烧水、取茶叶、泡茶……这一切看似简单,但背后却隐藏着复杂的AI技术。今天,我们就来揭秘BOTA六维力矩传感器在机器人操控…...
HDF5文件格式:数据类型与读写功能详解
HDF5文件格式:数据类型与读写功能详解 HDF5简介 HDF5(Hierarchical Data Format version 5)是一种用于存储和管理大量科学数据的文件格式和库。它由美国国家高级计算应用中心(NCSA)开发,具有以下特点&…...
macOS Chrome - 打开开发者工具,设置 Local storage
文章目录 macOS Chrome - 打开开发者工具设置 Local storage macOS Chrome - 打开开发者工具 方式2:右键点击网页,选择 检查 设置 Local storage 选择要设置的 url,显示右侧面板 双击面板,输入要添加的内容 2025-04-08ÿ…...
使用Vscode排除一些子文件搜索
打开用户/工作区设置 全局生效:打开命令面板(CtrlShiftP 或 CmdShiftP),搜索并选择 Preferences: Open User Settings (JSON)。 仅当前项目生效:在项目根目录下创建 .vscode/settings.json 文件(如果不存在…...
kubernetes 入门篇之架构介绍
经过前段时间的学习和实践,对k8s的架构有了一个大致的理解。 1. k8s 分层架构 架构层级核心组件控制平面层etcd、API Server、Scheduler、Controller Manager工作节点层Kubelet、Kube-proxy、CRI(容器运行时接口)、CNI(网络插件&…...
如何绕过WAF实现SQL注入攻击?
引言 在渗透测试中,SQL注入(SQLi)始终是Web安全的核心漏洞之一。然而,随着企业广泛部署Web应用防火墙(WAF),传统的注入攻击往往会被拦截。本文将分享一种绕过WAF检测的SQL注入技巧…...
