Search code examples
androidkotlinpicassonullableillegalargumentexception

Parameter specified as non-null is null - loading Image in Kotlin


I'm using Picassos Target to load a image from the Internet and generate a Color Palette out of it. When the image doesn't exist anymore, I get the following crash with the Error in the Logcat:

 java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter placeHolderDrawable
        at .ActivityThread.performLaunchActivity(ActivityThread.java:3260)
        at .ActivityThread.handleLaunchActivity(ActivityThread.java:3396)
        at .servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at .servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at .servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at .ActivityThread$H.handleMessage(ActivityThread.java:2009)
        at .Handler.dispatchMessage(Handler.java:107)
        at .Looper.loop(Looper.java:214)
        at .ActivityThread.main(ActivityThread.java:7319)
        at .reflect.Method.invoke(Native Method)
        at .os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at .os.ZygoteInit.main(ZygoteInit.java:934)
     Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter placeHolderDrawable
        at .LoadImage$onCreate$1.onPrepareLoad(Unknown Source:2)
        at com.squareup.picasso.RequestCreator.into(RequestCreator.java:559)
        at .LoadImage.onCreate(LoadImage.kt:154)
        **at .LoadImage.onCreate(LoadImage.kt:154)**

Ok, I understand what's going on - Picasso loads the image, the image is null and therefore the app crashes. But how can I handle this problem with a line of code?

This is the section where the problem happens, I marked line 154 for you:

    Picasso.get()
            .load(eventimgurl)
            **.into(object : com.squareup.picasso.Target {**
                override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) {
                    assert(iconImg != null)
                    iconImg!!.setImageBitmap(bitmap)
                    Palette.from(bitmap)
                            .generate(Palette.PaletteAsyncListener { palette ->
                                val dividerswatch_dom = palette!!.dominantSwatch
                                val dividerswatch_sub = palette.lightVibrantSwatch

                                if (dividerswatch_dom == null || dividerswatch_sub == null) {

                                    return@PaletteAsyncListener
                                }


                                val gd = GradientDrawable(
                                        GradientDrawable.Orientation.LEFT_RIGHT,
                                        intArrayOf(dividerswatch_dom.rgb, dividerswatch_sub.rgb))
                                gd.cornerRadius = 0f
                                gd.gradientType = GradientDrawable.RADIAL_GRADIENT
                                gd.gradientRadius = 700.0f


                                eventdividerheader.background = gd
                                eventdividerdjstart.background = gd
                                eventdivider_detail_top.background = gd
                                eventdivider_detail_bottom.background = gd

                            })
                }

                override fun onBitmapFailed(e: Exception, errorDrawable: Drawable) {

                }

                override fun onPrepareLoad(placeHolderDrawable: Drawable) {

                }
            })

Solution

  • Actually, the problem is that library code is not fully compatible with Kotlin. Or in fact, it's more about the IDE you use than the library.

    Why?

    interface Target {
        void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from)
        void onBitmapFailed(Exception e, Drawable errorDrawable)
        void onPrepareLoad(Drawable placeHolderDrawable)
    }
    

    The interface above would be the java interface of Target. As there are no null-annotations using this in Kotlin code can be quite tricky, because we don't know if the type of placeHolderDrawable (and other variables) is nullable or not.

    So, the kotlin implementation of this interface would be following:

    object : Target {
        // ...
        override fun onPrepareLoad(placeHolderDrawable: Drawable) {
        }
    }
    

    or...

    object : Target {
        // ...
        override fun onPrepareLoad(placeHolderDrawable: Drawable?) {
        }
    }
    

    And here we are. When Kotlin compiles to Java byte code it adds not-null checks for not-null types:

    kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull(param)
    

    So, to make your code work... just change Drawable to Drawable?. Then, there will be no Intrinsics call and there will be no exception.

    So, even if your method is empty compiler adds Intrinsics checks for all not null parameters at the beginning of the method. Feel free to decompile your code and find those calls in empty methods :)

    Conclusion The problem is that code without nullability annotations is not properly generated by IDE, as types are converted to nonnull types instead of nullable.