Try Finally blocks to ensure cleanup and prevent OOM crashes
This commit is contained in:
parent
f5c90f0e5c
commit
578e77421a
@ -91,18 +91,36 @@ class CameraCaptureManager(private val context: Context) {
|
|||||||
val (bytes, orientation) = capture.takeJpegWithExif(context.mainExecutor())
|
val (bytes, orientation) = capture.takeJpegWithExif(context.mainExecutor())
|
||||||
val decoded = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
|
val decoded = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
|
||||||
?: throw IllegalStateException("UNAVAILABLE: failed to decode captured image")
|
?: throw IllegalStateException("UNAVAILABLE: failed to decode captured image")
|
||||||
val rotated = rotateBitmapByExif(decoded, orientation)
|
|
||||||
val scaled =
|
// Wrap bitmap operations in try-finally to guarantee cleanup on all paths
|
||||||
|
val rotated = try {
|
||||||
|
rotateBitmapByExif(decoded, orientation)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
decoded.recycle()
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
// Note: if rotation was applied, decoded is already recycled; otherwise rotated === decoded
|
||||||
|
|
||||||
|
val scaled: Bitmap
|
||||||
|
val recycleRotatedSeparately: Boolean
|
||||||
|
try {
|
||||||
if (maxWidth != null && maxWidth > 0 && rotated.width > maxWidth) {
|
if (maxWidth != null && maxWidth > 0 && rotated.width > maxWidth) {
|
||||||
val h =
|
val h =
|
||||||
(rotated.height.toDouble() * (maxWidth.toDouble() / rotated.width.toDouble()))
|
(rotated.height.toDouble() * (maxWidth.toDouble() / rotated.width.toDouble()))
|
||||||
.toInt()
|
.toInt()
|
||||||
.coerceAtLeast(1)
|
.coerceAtLeast(1)
|
||||||
rotated.scale(maxWidth, h)
|
scaled = rotated.scale(maxWidth, h)
|
||||||
|
recycleRotatedSeparately = true
|
||||||
} else {
|
} else {
|
||||||
rotated
|
scaled = rotated
|
||||||
|
recycleRotatedSeparately = false
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
rotated.recycle()
|
||||||
|
throw e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
val maxPayloadBytes = 5 * 1024 * 1024
|
val maxPayloadBytes = 5 * 1024 * 1024
|
||||||
// Base64 inflates payloads by ~4/3; cap encoded bytes so the payload stays under 5MB (API limit).
|
// Base64 inflates payloads by ~4/3; cap encoded bytes so the payload stays under 5MB (API limit).
|
||||||
val maxEncodedBytes = (maxPayloadBytes / 4) * 3
|
val maxEncodedBytes = (maxPayloadBytes / 4) * 3
|
||||||
@ -134,6 +152,12 @@ class CameraCaptureManager(private val context: Context) {
|
|||||||
Payload(
|
Payload(
|
||||||
"""{"format":"jpg","base64":"$base64","width":${result.width},"height":${result.height}}""",
|
"""{"format":"jpg","base64":"$base64","width":${result.width},"height":${result.height}}""",
|
||||||
)
|
)
|
||||||
|
} finally {
|
||||||
|
scaled.recycle()
|
||||||
|
if (recycleRotatedSeparately) {
|
||||||
|
rotated.recycle()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user