I have a small application that wraps a website that processes pictures. I can not upload more than 5 pictures from my phone, the application crashes with error:
java.lang.OutOfMemoryError: Failed to allocate a xxxxx byte allocation.
How do I optimize memory management? I would greatly appreciate any advice.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == PICK_IMAGE_REQUEST_CODE && resultCode == RESULT_OK) { val selectedImageBlobs = mutableListOf<Triple<String, String, String>>() if (data?.clipData != null) { val clipData = data.clipData for (i in 0 until clipData!!.itemCount) { val uri = clipData.getItemAt(i).uri val base64Image = convertUriToBase64(uri) val mimeType = contentResolver.getType(uri) val fileName = getFileNameWithExtension(uri) if (base64Image != null && mimeType != null && fileName.isNotEmpty()) { selectedImageBlobs.add(Triple(base64Image, mimeType, fileName)) } } } else { val uri = data?.data if (uri != null) { val base64Image = convertUriToBase64(uri) val mimeType = contentResolver.getType(uri) val fileName = getFileNameWithExtension(uri) if (base64Image != null && mimeType != null && fileName.isNotEmpty()) { selectedImageBlobs.add(Triple(base64Image, mimeType, fileName)) } } } // Send selected image blobs, MIME types, and filenames to JSBridge jsBridge.sendImagePaths(selectedImageBlobs) } }
This function is where the image data is read from the device’s storage, converted to a Base64 string, and returned(consuming a significant amount of memory
private fun convertUriToBase64(uri: Uri): String? {
return try {
val inputStream: InputStream? = contentResolver.openInputStream(uri)
val byteArrayOutputStream = ByteArrayOutputStream()
val buffer = ByteArray(1024)
var bytesRead: Int
while (inputStream!!.read(buffer).also { bytesRead = it } != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead)
}
val byteArray = byteArrayOutputStream.toByteArray()
Base64.encodeToString(byteArray, Base64.DEFAULT)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
And then I send data:
private inner class JSBridge(val context: Context, private val webView: WebView) {
fun sendData(imageFiles: List<Triple<String, String, String>>) {
val jsonArray = JSONArray()
for (imageFile in imageFiles) {
val jsonObject = JSONObject()
jsonObject.put("type", imageFile.second)
jsonObject.put("name", imageFile.third)
jsonObject.put("blob", imageFile.first)
jsonArray.put(jsonObject)
}
val jsonData = """
{
"method": "upload_files_from_app",
"result": {
"imageFiles": $jsonArray
}
}
""".trimIndent()
val jsonObject = JSONObject(jsonData)
val jsonObjectString = jsonObject.toString()
Log.d("WebViewBridge", "JSBridge JSON Object: $jsonObjectString")
// Call JavaScript function with JSON data
webView.evaluateJavascript("javascript: window.mobile2web.onMessage($jsonObjectString)", null)
}