'App crashes when sending image to Firebase storage

So in my app i need profile images but when i select one it crashes my app. I added all the sdk's also tried fixing it by adding permission for Google photo's but that didn't help. I really have no idea what could have caused this problem I also added my bucket url so that doesn't give a problem or maybe I did this wrong? Here is my code.

Function to store the image:

    fun storeImage() {
        if (resultImageUrl != null && userId != null){
            val filePath = FirebaseStorage.getInstance("gs://dogsharev2-5e4c3.appspot.com").reference.child("profileImage").child(userId)
            var bitmap: Bitmap? = null
            try {
                if (android.os.Build.VERSION.SDK_INT >= 29){
                    // To handle deprecation use
                    val source = ImageDecoder.createSource(contentResolver,resultImageUrl!!)
                    bitmap = ImageDecoder.decodeBitmap(source)
                } else {
                    // Use older version
                    bitmap = MediaStore.Images.Media.getBitmap(application.contentResolver, resultImageUrl!!)

                }
            }catch (e: IOException){
                e.printStackTrace()
            }

            val baos = ByteArrayOutputStream()
            bitmap?.compress(Bitmap.CompressFormat.JPEG, 200, baos)
            val data = baos.toByteArray()

            val uploadTask = filePath.putBytes(data)
            uploadTask.addOnFailureListener {e -> e.printStackTrace()}
            uploadTask.addOnSuccessListener { taskSnapshot ->
                filePath.downloadUrl
                    .addOnSuccessListener { uri ->
                        profileFragment?.updateImageUri(uri.toString())
                    }
                    .addOnFailureListener { e -> e.printStackTrace()}
            }
        }
    }

function to start image activity:

    override fun startActivityForPhoto() {
        val intent = Intent(Intent.ACTION_PICK)
        intent.type = "image/*"
        getResult.launch(intent)
    }
    private val getResult =
        registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ){
            if (it.resultCode == Activity.RESULT_OK){
                resultImageUrl = it.data?.data
                storeImage()
            }
        }

I also got the errors :

2022-05-19 23:21:38.333 26824-26824/com.example.dogsharev2 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.dogsharev2, PID: 26824
    java.lang.IllegalArgumentException: quality must be 0..100
        at android.graphics.Bitmap.compress(Bitmap.java:1436)
        at com.example.dogsharev2.activities.TinderActivity.storeImage(TinderActivity.kt:155)
        at com.example.dogsharev2.activities.TinderActivity.getResult$lambda-0(TinderActivity.kt:132)
        at com.example.dogsharev2.activities.TinderActivity.$r8$lambda$jtOlPDH_wItpCc5GiEy42Z8DYno(Unknown Source:0)
        at com.example.dogsharev2.activities.TinderActivity$$ExternalSyntheticLambda0.onActivityResult(Unknown Source:4)
        at androidx.activity.result.ActivityResultRegistry$1.onStateChanged(ActivityResultRegistry.java:148)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
        at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:265)
        at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:307)
        at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:148)
        at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:134)
        at androidx.lifecycle.ReportFragment.dispatch(ReportFragment.java:68)
        at androidx.lifecycle.ReportFragment$LifecycleCallbacks.onActivityPostStarted(ReportFragment.java:187)
        at android.app.Activity.dispatchActivityPostStarted(Activity.java:1362)
        at android.app.Activity.performStart(Activity.java:8061)
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3475)
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

Thanks in advance.



Solution 1:[1]

This is where the problems are:

 for (Map.Entry<String, Object> entry : map.entrySet()) {
    if (entry.getKey().contains("/") 
        && !entry.getKey().contains("$ref")) {
        currentKey = entry.getKey();
        operation.put(entry.getKey(), params); // Here value is assigned
                                               // successfully
    }
    if (method.contains(entry.getKey())) {
         operation.get(currentKey).add(entry.getKey()); 
                                               // Here its null pointer
                                               // exception & HashMap has no data
    }
    ...
 }

The first test is testing the value of the key. The second test is testing whether the key is contained in methods. These tests are different.

Based on the code that you have shown us, there are actually 4 possibilities for the outcomes of these tests:

  • both tests succeed
  • both tests fail
  • first test succeeds, and second test fails
  • first test fails, and second test succeeds

The last possibility is the probably the cause of the NPE.

If (for example) the key does not contain the string "/", but it the method string (or collection or whatever) does contain the key, then:

  1. The operation.put... statement IS NOT executed
  2. The operation.get... statement IS executed ... and will NPE because the operation.get call returns null.

And there is this is exacerbated by a second problem. When the first test fails, it won't perform the currentKey = entry.getKey(); statement. That means that operation.get(currentKey) will be using a currentKey value from a previous step. The value could even be null. (Note that operation.get(null) will most likely return null.)


In short, your code appears to contain at least two bugs, and the most plausible explanation for the missing operation map entry is that your code didn't put it there! (It is not becoming null.)

(We do not need to hypothesize a flaw in HashMap to explain this.)

If this doesn't explain the problem to your satisfaction, you will need to add a minimal reproducible example to your question ... so that we can run it ourselves.

Solution 2:[2]

You aren't being consistent with currentKey and your second if is wrong. You are testing method but then invoking on operation. Let's fix that. Like,

HashMap<String, List<String>> operation = new HashMap<>();
List<String> method = Arrays.asList("get", "put", "post");
for (Map.Entry<String, Object> entry : map.entrySet()) {
    String currentKey = entry.getKey();
    if (currentKey.contains("/") && !currentKey.contains("$ref")) {
        operation.put(currentKey, new ArrayList<>());
    }
    if (operation.containsKey(currentKey)) {
        operation.get(currentKey).add(currentKey);
    }

    if (entry.getValue() instanceof Map) {
        iterate((Map<String, Object>) entry.getValue());
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Elliott Frisch