Image exists, not null, but I get an NullPointerEx

2019-07-28 11:43发布

问题:

Short introduction

The app I am working on at the moment, takes an image from a JSON, if correct it uses it and saves it as a loading image on next use.

Problem

All of the sudden, the app started crashing on loading and on further inspection, the file.isFile && file.canRead() check I had in place returns positive but it still crashes on BitmapFactory.decodeStream. The byte count of the file is 8k, compared to other devices I've used, where that same image actually has 43k bytes.

The image json is part of a much larger json message (approx 500kb) and it's not at the start or the end. The last use before this happened there was no problem loading or sign showing that download might have stopped half way. Even so, the image still has 8kb so I imagine it should just create something with the part it has rather then throwing NullPointerException

I am using Android Studio 3.0 Beta 4 and code is in Kotlin. I must have run it on this device 100 times, and even after this occurred it runs perfectly fine on other test devices, plus the iOS app that gets the exact same json at start up

What I am looking for

Advice on how to deal with the issue, or information whether it's a known bug in Android or Kotlin. I can probably reinstall the app on the device and it will be ok again but would not want this happening once the app was released, if I can prevent it.

LaterEdit: With Xaviers suggestion, I have copied the file onto the desktop and it's definitely malformed, when it loads it actually shows some seriously malformed image of things running on the Mac. I have tried to upload it but it just displays as an empty white image. It still has 8kb, so it contains some data. How is this possible and can it be prevented?

Code

Loading up the app, I check if image exists and load it into an imageView

try {
     if (DesignSupport().imageExists("logo", this)) {
         if (DesignSupport().loadImage("logo", this) != null) {
             imageView.setImageBitmap(DesignSupport().loadImage("logo", this))
         }
     }
 } catch (error: Error) {
     Log.i(tag, error.stackTrace.toString())
 }

Check if image exists

fun imageExists(string: String, context: Context) : Boolean {
        val path = android.os.Environment.getExternalStorageDirectory().toString() + "/" + context.applicationInfo.name + "/" + string + ".png"
        val file = File(path)
        return (file.isFile && file.canRead())
    }

Load up the image

    fun loadImage(string: String, context: Context) : Bitmap {
            val path = android.os.Environment.getExternalStorageDirectory().toString() + "/" + context.applicationInfo.name + "/" + string + ".png"
            val fis = FileInputStream(path)
// it crashes at the next line, but when I print fis.available() it returns 8200
            return BitmapFactory.decodeStream(fis)
        }

Crash Log

 java.lang.RuntimeException: Unable to start activity ComponentInfo{.GeneralAccessScreens.startupScreen}: java.lang.IllegalStateException: BitmapFactory.decodeStream(fis) must not be null
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2412)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2470)
at android.app.ActivityThread.access$900(ActivityThread.java:174)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1307)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5593)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: BitmapFactory.decodeStream(fis) must not be null
at SupportMethods.DesignSupport.loadImage(DesignSupport.kt:45)
at .GeneralAccessScreens.startupScreen.onCreate(startupScreen.kt:34)
at android.app.Activity.performCreate(Activity.java:5458)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093)

Import statements

import android.app.Activity
import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Base64
import android.util.Log
import android.view.inputmethod.InputMethodManager
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream

回答1:

The specific exception is thrown because BitmapFactory.decodeStream(fis) returns null while the function is specified to return a non-nullable object. Either make the return value nullable or define an appropriate replacement if it does return null.

In the background Kotlin generates the following "java" code:

Bitmap tmp = BitmapFactory.decodeStream(fis);
Intrinsics.checkExpressionValueIsNotNull(tmp, "BitmapFactory.decodeStream(fis)");
return tmp;

The source of the exception is the Intrinsics.checkExpressionValueIsNotNull call.



回答2:

Are you sure the crash is in the same loadImage() method and not on another one? In the error log it says that the crash is in BitmapFactory.decodeReso…ystem(), R.drawable.logo), which seems a different one.

Also, have you tried to do a Rebuild first? I've seen many problems in AS 3.0 betas that are resolved by doing that.

From documentation, even if fis is null it should not crash with this error, just return a null (emphasis is mine).

Decode an input stream into a bitmap. If the input stream is null, or cannot be used to decode a bitmap, the function returns null. The stream's position will be where ever it was after the encoded data was read.

Just to discard things, can you add the import statement for BitmapFactory? Should be import android.graphics.BitmapFactory.