Rajesh Jadav
Rajesh Jadav

Reputation: 12861

Kotlin - IllegalArgumentException: Parameter specified as non-null is null

I am passing data to some fragment in bundle and while receiving it throws the exception. This error occurs while restoring Fragment's state.

Error occurs in Intrinsics.checkParameterIsNotNull when createFromParcel is called. This happen with all non-nullable fields in Model.

Caused by java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.b.h.b, parameter realtorImageUrl
   at com.android.app.ui.common.model.Property.(Unknown Source:16)
   at com.android.app.ui.common.model.Property$Creator.createFromParcel(Unknown Source:637)
   at android.os.Parcel.readParcelable(Parcel.java:2797)
   at android.os.Parcel.readValue(Parcel.java:2691)
   at android.os.Parcel.readArrayMapInternal(Parcel.java:3058)
   at android.os.BaseBundle.unparcel(BaseBundle.java:257)
   at android.os.BaseBundle.getInt(BaseBundle.java:961)
   at me.yokeyword.fragmentation.SupportFragmentDelegate.onCreate(SourceFile:93)
   at me.yokeyword.fragmentation.SupportFragment.onCreate(SourceFile:48)
   at android.support.v4.app.Fragment.performCreate(SourceFile:2331)
   at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1386)
   at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(SourceFile:1759)
   at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1827)
   at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(SourceFile:3244)
   at android.support.v4.app.FragmentManagerImpl.dispatchCreate(SourceFile:3194)
   at android.support.v4.app.Fragment.restoreChildFragmentState(SourceFile:1444)
   at android.support.v4.app.Fragment.onCreate(SourceFile:1415)
   at me.yokeyword.fragmentation.SupportFragment.onCreate(SourceFile:47)
   at android.support.v4.app.Fragment.performCreate(SourceFile:2331)
   at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1386)
   at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(SourceFile:1759)
   at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1827)
   at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(SourceFile:3244)
   at android.support.v4.app.FragmentManagerImpl.dispatchCreate(SourceFile:3194)
   at android.support.v4.app.FragmentController.dispatchCreate(SourceFile:184)
   at android.support.v4.app.FragmentActivity.onCreate(SourceFile:355)
   at android.support.v7.app.AppCompatActivity.onCreate(SourceFile:84)
   at me.yokeyword.fragmentation.SupportActivity.onCreate(SourceFile:38)
   at com.android.app.ui.home.HomeActivity.onCreate(SourceFile:47)
   at android.app.Activity.performCreate(Activity.java:7174)
   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2908)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3030)
   at android.app.ActivityThread.-wrap11(Unknown Source)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
   at android.os.Handler.dispatchMessage(Handler.java:105)
   at android.os.Looper.loop(Looper.java:164)
   at android.app.ActivityThread.main(ActivityThread.java:6938)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

Property.kt

@Parcelize
data class Property(
    ...
    @Json(name = "RealtorImageUrl")
    val realtorImageUrl: String
    ...
) : Parcelable

Kotlin 1.1.4, Android Extensions plugin provides Parcelable implementation generator using @Parcelize.

PropertyListFragment.kt

override fun showPropertyDetails(property: Property) {
    (parentFragment as PropertySearchResultFragment).start(
        PropertyDetailsFragment.newInstance(property)
    )
}

PropertyDetailsFragment.kt

class PropertyDetailsFragment{
    ...
    companion object {
        fun newInstance(property: Property) = PropertyDetailsFragment().withArgs {
            putParcelable(INT_EXTRA_PROPERTY, property)
        }
    }
    ...
}

What do I need to do to fix the issue?

Upvotes: 5

Views: 5696

Answers (3)

Matej Vukosav
Matej Vukosav

Reputation: 666

Can u try using @field:Json(name = "RealtorImageUrl") and check if it works then?

Also, check if you have added proper factory KotlinJsonAdapterFactory()

 val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .build()

Upvotes: 0

aminography
aminography

Reputation: 22832

Since the realtorImageUrl is defined not null, so kotlin does not permit to set it to null. Therefore the only possible way to do that is to set the null value by reflection. Json helper libraries are based on annotation processing and using reflection for setting value to the fields, so the problem definitely comes from them.

  • First of all, I highly recommend you to use google Gson.
  • Second, be sure that the json string is not null or empty after configuration changes.
  • Third, be sure that you are using moshi-kotlin (not simple moshi) in dependencies and adding an instance of KotlinJsonAdapterFactory to the moshi builder.

build.gradle:

implementation 'com.squareup.moshi:moshi-kotlin:1.8.0'

Test:

val json = "{\"RealtorImageUrl\": \"http://www.gstatic.com/tv/thumb/persons/667736/667736_v9_ba.jpg\"}"

val moshi = Moshi.Builder()
        .add(KotlinJsonAdapterFactory()) // com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
        .build()

val jsonAdapter = moshi.adapter(Property::class.java) as JsonAdapter<Property>
val property = jsonAdapter.fromJson(json) as Property

supportFragmentManager.beginTransaction()
        .replace(R.id.container, PropertyDetailsFragment.newInstance(property))
        .commit()

It is better to use withArguments from anko to put arguments for the fragment:

PropertyDetailsFragment.kt:

class PropertyDetailsFragment : Fragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val property = arguments?.getParcelable(KEY_EXTRA_PROPERTY) as Property
        val realtorImageUrl = property.realtorImageUrl
    }

    companion object {
        private const val KEY_EXTRA_PROPERTY = "KEY_EXTRA_PROPERTY"

        fun newInstance(property: Property) = PropertyDetailsFragment().withArguments(
                KEY_EXTRA_PROPERTY to property
        )
    }
}

Upvotes: 3

Birju Vachhani
Birju Vachhani

Reputation: 6373

Well, this might not be the perfect solution but it can solve your issue. You can make your property nullable and just add a null check whenever you access them.

Just initialize you variable like this

Property.kt

@Parcelize
data class Property(
    ...
    @Json(name = "RealtorImageUrl")
    val realtorImageUrl: String
    ...
) : Parcelable

PropertyListFragment.kt

override fun showPropertyDetails(property: Property?) {
    (parentFragment as PropertySearchResultFragment).start(
        PropertyDetailsFragment.newInstance(property)
    )
}

And in PropertyDetailsFragment.kt

class PropertyDetailsFragment{
    ...
    companion object {
        fun newInstance(property: Property?) = PropertyDetailsFragment().withArgs {
            property?.let{
                putParcelable(INT_EXTRA_PROPERTY, property)
            }
        }
    }
    ...
}

Upvotes: 0

Related Questions