使用Android Navigation Component时如何在两个Fragment之间传递Bitmap?
Android 照片编辑器Fragment间传递图片数据解决方案
现有方案问题根因
- 直接传带Bitmap的Parcelable对象报错:Android Binder事务缓冲区默认上限仅1MB左右,高分辨率Bitmap体积远超阈值,触发
TransactionTooLargeException异常 - 存缓存传Uri跳转慢:跳转逻辑阻塞在Bitmap压缩、写入磁盘的IO操作完成后才执行,加上默认PNG无损压缩速度慢、冗余目录判断等问题,进一步拉长等待时间
优化方案
方案1:使用Activity级共享ViewModel传递(最优)
同一Activity下的不同编辑Fragment共享作用域绑定到Activity的ViewModel,直接在内存中传递Bitmap,完全跳过IO操作,无跳转延迟:
// 自定义Activity作用域的共享ViewModel class SharedEditViewModel : ViewModel() { // 存储当前编辑中的Bitmap val editingBitmap = MutableLiveData<Bitmap?>() // 存储数据类型标记 val dataType = MutableLiveData<ActiveNavArgsData>() } // 源Fragment跳转逻辑 binding.editorIncludeId.crop.setOnClickListener { // 直接赋值内存数据,无需等待IO sharedEditViewModel.editingBitmap.value = mainEditViewModel._imgSrc.value sharedEditViewModel.dataType.value = ActiveNavArgsData.BITMAP // 立即执行跳转 findNavController().navigate( MainEditScreenFragmentDirections.mainEditScreenFragmentToCropFragment(), getSharedElementExtra() ) } // 目标Fragment取数逻辑 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedEditViewModel.editingBitmap.value?.let { bitmap -> // 直接使用Bitmap执行裁剪等操作 } // 操作完成后可手动置空,回收内存 sharedEditViewModel.editingBitmap.value = null }
方案2:优化缓存存储逻辑(必须传Uri时使用)
对现有存储工具类做如下优化,可将存储速度提升3~5倍:
- 缓存存储逻辑去除冗余的外部目录判断逻辑
- 编辑中间环节默认使用JPG 80~90压缩质量,替代默认PNG无损压缩
- 固定缓存文件名,避免重复创建文件的开销
优化后代码示例:
fun savePhotoInCacheDir(bitmap: Bitmap): Uri { val cacheFile = File(context.cacheDir, "temp_edit.jpg") FileOutputStream(cacheFile).use { fos -> bitmap.compress(Bitmap.CompressFormat.JPEG, 85, fos) } return Uri.fromFile(cacheFile) }
同时可调整跳转逻辑:先跳转,再在目标Fragment异步加载缓存Uri,跳转时加个轻量加载动画,用户无感知。
内容的提问来源于stack exchange,提问作者Wasim
相关产品推荐
相关产品推荐

