如何在两个片段之间传递位图? (我正在使用 Android 导航组件)
Posted
技术标签:
【中文标题】如何在两个片段之间传递位图? (我正在使用 Android 导航组件)【英文标题】:How to pass Bitmap between two fragment ? ( I am using Android Navigation Component ) 【发布时间】:2022-01-02 20:28:23 【问题描述】:我正在构建一个照片编辑器。对于绘画、调整、裁剪等,我创建了片段。我面临传递位图和 Uri 我面临下面描述的问题。
首先,我应用了两个方法一个
-
首先我传递了一个对象,它是
CommonParcelData
@Parcelize data class CommonParcelData( val uri:Uri?=null,val bitmap: Bitmap?=null, val availableData: ActiveNavArgsData, var isResize:Boolean=false ): Parcelable
problem 是当我使用 CommonParcelData
数据类传递数据时,我会显示 error 像 java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 17488344 bytes
和 JavaBinder: !!! FAILED BINDER TRANSACTION !!!
因为我传递了位图对象。然后我选择我的第二种方法。
第二种方法是我将 edited bitmap 和 android 转换为 uri 并保存在缓存目录中并将 uri 发送到目的地/其他片段,但 这个方法的问题是片段转换非常慢。为了简化,我创建了一个转换将位图保存到存储中并获取 uri 该类是 SaveBitmapInStorage
类 SaveBitmapInStorage(private val context: Context)
companion object
private val TAG = SaveBitmapInStorage::class.java.simpleName
var compressionQuality = 100
set(value)
if (value in 0..100)
field = value
else
throw Exception("compressionQuality value must be between 0 to 100")
private var imgExtension = ImgExtension.PNG.name.lowercase()
fun changeImgExtension(imgType: ImgExtension)
imgExtension = imgType.name.lowercase()
private val dirName = context.getString(R.string.app_name)
private val appName = dirName
private val folder =
File(context.getExternalFilesDir(null)?.parentFile?.parentFile?.parentFile?.parentFile?.path + File.separator + appName)
/** It must be execute on background thread */
fun save(bitmap: Bitmap, isSaveInCacheDir: Boolean = false): Uri
if (!folder.isDirectory)
folder.mkdir()
Log.d(TAG, " file created :-> $folder")
val imgFile = if (isSaveInCacheDir) File(context.cacheDir, getCacheImgFile)
else File(folder, "$appName$System.currentTimeMillis().$imgExtension")
try
val fileOutputStream = FileOutputStream(imgFile)
checkImgFormat(bitmap, fileOutputStream)
fileOutputStream.apply
flush();
close()
catch (e: IOException)
e.printStackTrace();
finally
return Uri.fromFile(imgFile)
private fun checkImgFormat(bitmap: Bitmap, fos: FileOutputStream)
when (imgExtension)
ImgExtension.PNG.name.lowercase() ->
bitmap.compress(Bitmap.CompressFormat.PNG, compressionQuality, fos)
ImgExtension.JPG.name.lowercase() ->
bitmap.compress(Bitmap.CompressFormat.JPEG, compressionQuality, fos)
private val getCacheImgFile = "$context.getString(R.string.cache_img_name).$imgExtension"
/** This should be in background thread ... */
fun savePhotoInCacheDir(bitmap: Bitmap): Uri
return save(bitmap, true)
在 ViewModel 中
fun savePhotoInCacheStorage(result: (resultUri: Uri) -> Unit)
CoroutineScope(Dispatchers.IO).launch
val uri = saveBitmapInStorage.savePhotoInCacheDir(_imgSrc.value!!)
withContext(Dispatchers.Main)
result(uri)
在 UI 中意味着在 Fragment 中
binding.editorIncludeId.crop.setOnClickListener
mainEditViewModel.savePhotoInCacheStorage
val data =CommonParcelData(it,availableData = ActiveNavArgsData.URI)
val action = MainEditScreenFragmentDirections
.mainEditScreenFragmentToCropFragment(data)
findNavController().navigate(action,getSharedElementExtra())
【问题讨论】:
【参考方案1】:你也可以用这种方式传递Bitmap。首先将Bitmap转换为Byte数组,然后将该Byte数组编码为String 像这样,
val outputStream = ByteArrayOutputStream()
bmp.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
val b = outputStream.toByteArray()
val encodedBitmap = Base64.encodeToString(b, Base64.DEFAULT)
然后你可以将它作为 Intent extra 传递。
要将字符串解码回位图,您可以这样做,
val b = Base64.decode(previouslyEncodedImage, Base64.DEFAULT)
val bitmap = BitmapFactory.decodeByteArray(b, 0, b.length)
previousEncodedImage
是您将从 Intent 中检索到的字符串值。
【讨论】:
是的,它有效。但是我的问题没有解决,因为我在第二个方法中描述了这意味着它将解决JavaBinder: !!! FAILED BINDER TRANSACTION !!!
问题,但两个片段之间的事务时间很慢。以上是关于如何在两个片段之间传递位图? (我正在使用 Android 导航组件)的主要内容,如果未能解决你的问题,请参考以下文章