Android Fragment中拍照显示至ImageView遇TransactionTooLargeException问题求助
错误原因
TransactionTooLargeException触发的核心原因是:Activity停止时,Fragment的状态数据(如Bundle中存储的Bitmap)超过了Binder事务的大小限制(约1MB)。你调用的getResizedBitmap()虽能压缩图片,但如果Bitmap被保存在Fragment的状态Bundle中(Navigation组件会自动处理状态保存),依然会触发异常。另外,你直接修改Bitmap宽高的photo!!.height = 150和photo!!.width = 120完全无效——因为Bitmap是不可变对象,这类代码不会改变图片尺寸,还可能引发潜在问题。
解决方案
1. 移除无效代码
直接删掉photo!!.height = 150和photo!!.width = 120两行无意义代码。
2. 改用指定文件路径拍照
ACTION_IMAGE_CAPTURE通过Intent返回的缩略图不仅尺寸有限,还会增加Intent的数据体积。正确做法是指定图片保存的本地文件路径,拍照后直接从文件读取图片,避免通过Intent传递Bitmap数据。
3. 状态保存时存储文件路径而非Bitmap
Fragment重建时,通过存储的文件路径重新加载图片,避免把Bitmap序列化到Bundle中,从根源上减少状态数据的体积。
修改后的完整代码示例
private lateinit var photoFile: File private val CAMERA_REQUEST = 100 private val MY_CAMERA_PERMISSION_CODE = 200 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.clickPhotoImageview.setOnClickListener { if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) { ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.CAMERA), MY_CAMERA_PERMISSION_CODE) } else { dispatchTakePictureIntent() } } // Fragment重建时加载之前保存的图片 savedInstanceState?.getString("PHOTO_PATH")?.let { path -> val bitmap = getResizedBitmap(BitmapFactory.decodeFile(path), 200) binding.clickPhotoImageview.setImageBitmap(bitmap) } } private fun dispatchTakePictureIntent() { Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent -> // 创建保存图片的临时文件 photoFile = createImageFile() photoFile.also { val photoURI = FileProvider.getUriForFile( requireContext(), "${requireContext().packageName}.fileprovider", it ) takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI) startActivityForResult(takePictureIntent, CAMERA_REQUEST) } } } private fun createImageFile(): File { val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) val storageDir: File? = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES) return File.createTempFile( "JPEG_${timeStamp}_", ".jpg", storageDir ) } @Deprecated("Deprecated in Java") override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String?>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == MY_CAMERA_PERMISSION_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(requireContext(), "camera permission granted", Toast.LENGTH_LONG).show() dispatchTakePictureIntent() } else { Toast.makeText(requireContext(), "camera permission denied", Toast.LENGTH_LONG).show() } } } @Deprecated("Deprecated in Java") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == CAMERA_REQUEST && resultCode == Activity.RESULT_OK) { // 从本地文件加载图片并压缩 val bitmap = BitmapFactory.decodeFile(photoFile.absolutePath) val resizedBitmap = getResizedBitmap(bitmap, 200) binding.clickPhotoImageview.setImageBitmap(resizedBitmap) } } fun getResizedBitmap(image: Bitmap, maxSize: Int): Bitmap? { var width = image.width var height = image.height val bitmapRatio = width.toFloat() / height.toFloat() if (bitmapRatio > 1) { width = maxSize height = (width / bitmapRatio).toInt() } else { height = maxSize width = (height * bitmapRatio).toInt() } return Bitmap.createScaledBitmap(image, width, height, true) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) // 保存图片文件路径而非Bitmap if (::photoFile.isInitialized) { outState.putString("PHOTO_PATH", photoFile.absolutePath) } }
额外配置说明
需要在AndroidManifest.xml中注册FileProvider:
<application> ... <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
然后在res/xml目录下创建file_paths.xml文件:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="my_images" path="Pictures" /> </paths>
内容的提问来源于stack exchange,提问作者Jajatee Nandinee Sahoo
相关产品推荐
相关产品推荐

