gesuwall gesuwall - 2 months ago 11
Android Question

Thrown exception while compressing bitmap inside AsyncTask is not stopping execution

I have an

AsyncTask
written in Kotlin that processes a bitmap and the stores it to a file in internal storage. My phone has no free space for the new bitmap, so during the write, an IOException is thrown, which should make the app crash.

This is my
doInBackground()
function:

override fun doInBackground(vararg params: Int?): Exception? {
if(params[0] == null)
throw IllegalArgumentException();
Log.d("PhotoEditTask", "start")
var bitmap : Bitmap? = null
val degrees = if(params.size == 0) 0 else params[0] ?: 0
bitmap = BitmapProcessing.getBitmapFromUri(sourceUri, resolver)
if (bitmap != null) {
bitmap = BitmapProcessing.rotateBitmap(bitmap, degrees)
var destFile = File(destPath)
destFile.delete()
BitmapFile.saveBitmapToFile(bitmap, destFile, 85)
Log.d("PhotoEditTask", "save successfull!")
return null
}
bitmap?.recycle()

return Exception("Write failed")

}


and the function that writes the file to a Bitmap is:

fun saveBitmapToFile(source: Bitmap, dest: File, quality: Int) {
var fout : FileOutputStream? = null
fout = FileOutputStream(dest)
source.compress(Bitmap.CompressFormat.PNG, quality, fout)
fout.flush()
fout.close()
Log.d("BitmapProcessing", "fout is closed")

}


This should crash, or at the very least return an Exception with the "Write failed" message, but it should never return null since my phone can't write the file. However the log shows otherwise:

09-09 12:16:40.824 26074-26805/com.criptext.uisample D/skia: jpeg_decoder finish successfully, L:1881!!!
09-09 12:16:40.833 26074-26805/com.criptext.uisample W/System.err: java.io.IOException: write failed: ENOSPC (No space left on device)
09-09 12:16:40.836 26074-26805/com.criptext.uisample W/System.err: at libcore.io.IoBridge.write(IoBridge.java:499)
09-09 12:16:40.836 26074-26805/com.criptext.uisample W/System.err: at java.io.FileOutputStream.write(FileOutputStream.java:187)
09-09 12:16:40.837 26074-26805/com.criptext.uisample W/System.err: at android.graphics.Bitmap.nativeCompress(Native Method)
09-09 12:16:40.837 26074-26805/com.criptext.uisample W/System.err: at android.graphics.Bitmap.compress(Bitmap.java:1013)
09-09 12:16:40.837 26074-26805/com.criptext.uisample W/System.err: at com.criptext.monkeykitui.util.BitmapFile.saveBitmapToFile(BitmapFile.java:18)
09-09 12:16:40.837 26074-26805/com.criptext.uisample W/System.err: at com.criptext.monkeykitui.input.photoEditor.PhotoEditTask.doInBackground(PhotoEditTask.kt:42)
09-09 12:16:40.838 26074-26805/com.criptext.uisample W/System.err: at com.criptext.monkeykitui.input.photoEditor.PhotoEditTask.doInBackground(PhotoEditTask.kt:17)
09-09 12:16:40.838 26074-26805/com.criptext.uisample W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:288)
09-09 12:16:40.838 26074-26805/com.criptext.uisample W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
09-09 12:16:40.839 26074-26805/com.criptext.uisample W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
09-09 12:16:40.840 26074-26805/com.criptext.uisample W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
09-09 12:16:40.840 26074-26805/com.criptext.uisample W/System.err: at java.lang.Thread.run(Thread.java:848)
09-09 12:16:40.840 26074-26805/com.criptext.uisample W/System.err: Caused by: libcore.io.ErrnoException: write failed: ENOSPC (No space left on device)
09-09 12:16:40.842 26074-26805/com.criptext.uisample W/System.err: at libcore.io.Posix.writeBytes(Native Method)
09-09 12:16:40.842 26074-26805/com.criptext.uisample W/System.err: at libcore.io.Posix.write(Posix.java:202)
09-09 12:16:40.843 26074-26805/com.criptext.uisample W/System.err: at libcore.io.BlockGuardOs.write(BlockGuardOs.java:197)
09-09 12:16:40.843 26074-26805/com.criptext.uisample W/System.err: at libcore.io.IoBridge.write(IoBridge.java:494)
09-09 12:16:40.843 26074-26805/com.criptext.uisample W/System.err: ... 11 more
09-09 12:16:40.843 26074-26805/com.criptext.uisample D/skia: ------- write threw an exception
09-09 12:16:40.844 26074-26805/com.criptext.uisample D/BitmapToFile: fout is closed
09-09 12:16:40.844 26074-26805/com.criptext.uisample D/PhotoEditTask: save successfull!
09-09 12:16:40.844 26074-26074/com.criptext.uisample D/PhotoEditTask: result: null


According to the Log, the
IOException
is thrown and it is caught somewhere, but the execution is never interrupted, so it always returns null. What is going on? How can I handle the
IOException
??

Answer

The Bitmap class compress() method intentionally does not throw an exception on failure.

The documentation lists no exceptions for this method, and instead lists the expected return value as:

Returns: boolean true if successfully compressed to the specified stream.

That is why you see your line of logging output of "fout is closed" since no exception is thrown and there is no checking of the boolean result.

The line of code calling compress() needs to check the boolean results:

if (!source.compress(Bitmap.CompressFormat.PNG, quality, fout)) {
    throw IOException("compression failure")
}
Comments