Android 获取多Activity返回的图片音频数据合成视频实现方案
需求实现方案解答
第一种顺序启动选择器的写法是否可行?
完全不可行。ActivityResultLauncher.launch()是异步非阻塞调用,在onClick里连续调用两个launch方法时,不会等待第一个选图流程走完返回结果,会直接同时拉起两个系统选择器;且执行到process()逻辑时,image和audio变量还未拿到选择结果赋值,必然出现空指针或逻辑错乱。
拆分ActivityResult回调的实现思路正确,图片数据暂存方案
你当前的拆分回调思路是符合Android系统交互逻辑的,暂存已选图片Uri不需要复杂的持久化操作,根据项目架构选对应方案即可:
方案1:普通页面场景用页面级变量暂存(最通用)
直接在Activity/Fragment中定义可空的页面级变量存储选中的图片Uri即可,正常跳转音频选择器的短流程中,系统不会销毁当前页面回收该变量:
// 定义页面级临时变量,生命周期和当前页面绑定 private var selectedImageUri: Uri? = null // 图片选择回调 private val getImage = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> uri ?: return@registerForActivityResult // 用户取消选图直接终止流程 // 将拿到的图片Uri存入临时变量 selectedImageUri = uri // 拉起音频选择器 getAudio.launch("audio/*") } // 音频选择回调 private val getAudio = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> uri ?: return@registerForActivityResult // 用户取消选音频直接终止流程 val targetImage = selectedImageUri ?: return@registerForActivityResult // 两个素材都获取完成,执行视频合成逻辑 process(targetImage, uri) // 合成触发后清空临时变量,避免数据残留 selectedImageUri = null } // 按钮点击入口 fun onTriggerClick() { // 每次点击先清空上一次操作的残留数据 selectedImageUri = null getImage.launch("image/*") }
极端场景兼容:如果担心系统内存不足时,在用户选音频的过程中回收当前Activity,只需要在
onSaveInstanceState方法中把selectedImageUri存入Bundle,页面重建时从Bundle读取恢复即可。Uri本身实现了Parcelable接口,直接存入Bundle没有序列化问题。
方案2:MVVM架构场景存在ViewModel中
如果页面用ViewModel管理状态,直接把临时选中的图片Uri存在ViewModel的状态变量里即可,屏幕旋转、页面配置变更时数据不会丢失,稳定性更高:
class VideoComposeViewModel : ViewModel() { val selectedImageUri = MutableStateFlow<Uri?>(null) // 其余合成相关状态逻辑 }
选图完成后把Uri赋值给ViewModel中的selectedImageUri,音频选择完成后直接从ViewModel中读取该值传入合成方法即可,不需要额外处理状态保存。
需避开的错误方案
- 不要把Uri转成真实文件路径存储,Android 10以上分区存储机制下无法直接拿到媒体文件真实路径,还会额外增加存储权限申请成本
- 不要把图片解码成Bitmap存在静态变量中,大Bitmap容易触发OOM,应用被后台回收时静态变量会直接丢失
内容的提问来源于stack exchange,提问作者Augustin Pan
相关产品推荐
相关产品推荐

