Kotlin - IllegalArgumentException: параметр, указанный как ненулевой, имеет значение NULL

Я передаю данные некоторому фрагменту в связке, и при его получении выдается исключение. Эта ошибка возникает при восстановлении состояния фрагмента.

Ошибка возникает в Intrinsics.checkParameterIsNotNull при вызове createFromParcel. Это происходит со всеми полями, не допускающими значения NULL, в 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 предоставляет генератор реализации Parcelable с использованием @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)
        }
    }
    ...
}

Что мне нужно сделать, чтобы исправить проблему?

stackoverflow.com/questions/49323455/…
AskNilesh 29.10.2018 06:53

Нет, ты не можешь быть уверен. ошибка заключается в том, что ваш realtorImageUrl, который вы указали как ненулевое, по какой-то причине получает значение null. вы могли бы принять его как lateinit var, который все еще не инициализирован при доступе.

Jeel Vankhede 29.10.2018 06:53

@NileshRathod Ссылка, которую вы предоставили, - это другая проблема. При доступе к java-классам в kotlin все переменные равны нулю, поэтому вам нужно использовать "?" при доступе к любой переменной java. Я не знаю, как параметр в модели получил значение null.

Rajesh 29.10.2018 07:05

Вы говорите I know realtorImageUrl is not null, но ясно, что он может быть нулевым.

EpicPandaForce 29.10.2018 07:43

@EpicPandaForce Я хочу сказать, что данные не являются нулевыми, когда они отображаются. Я хочу знать причину, по которой он стал нулевым.

Rajesh 29.10.2018 08:00

1) как вы определяете realtorImageUrl? 2) как вы взаимодействуете с realtorImageUrl? в каком методе (или методе переопределения)?

ariefbayu 29.10.2018 10:05

Пожалуйста, опубликуйте код о том, как вы взаимодействуете с realtorImageUrl и как вы устанавливаете / извлекаете его из посылки.

Eric Martori 29.10.2018 10:45

@ariefbayu Я добавил подробностей.

Rajesh 29.10.2018 10:52

@EricMartori Я добавил больше деталей.

Rajesh 29.10.2018 10:52

Проверяли ли вы, что Property правильно настроен и что realtorImageUrl не равен нулю, прежде чем добавлять его в качестве дополнительного свойства? Кажется, что вы получаете в нем нулевое значение, которое с вашими определениями могло произойти только при создании экземпляра Property.

Eric Martori 29.10.2018 11:12

Как вы звоните showPropertyDetails(property: Property)? Вполне возможно, что showPropertyDetails() вызывается до установки property / realtorImageUrl. Это проблема lateinit, вы должны убедиться, что переменная уже установлена ​​и установлена ​​в правильном порядке.

ariefbayu 30.10.2018 01:02

Вы пытались установить свойство как допускающее значение NULL - val realtorImageUrl: String??

Andrey Turkovsky 30.10.2018 09:37

Проблема может быть в парсинге Json, всякий раз, когда JsonResponse не имеет RealtorImageUrl, он будет рассматривать его как null

Lalit Jadav 16.11.2018 14:02
5
13
4 992
3

Ответы 3

Поскольку realtorImageUrl определен как ненулевой, поэтому kotlin не позволяет установить его как null. Поэтому единственный возможный способ сделать это - установить нулевое значение путем отражения. Вспомогательные библиотеки Json основаны на обработке аннотаций и использовании отражения для установки значений в поля, поэтому проблема определенно исходит от них.

  • Прежде всего, я настоятельно рекомендую вам использовать Google Gson.
  • Во-вторых, убедитесь, что строка json не является пустой или пустой после изменения конфигурации.
  • В-третьих, убедитесь, что вы используете moshi-kotlin (а не просто moshi) в зависимостях и добавляете экземпляр KotlinJsonAdapterFactory в компоновщик moshi.

build.gradle:

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

Тестовое задание:

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()

Лучше использовать withArguments из Анко, чтобы указать аргументы для фрагмента:

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
        )
    }
}

@Rajesh: Что такое библиотека с аннотацией @Json? Я тестировал его с помощью Google Gson, и никаких проблем с восстановлением состояния фрагмента, например поворота телефона, не возникло.

aminography 12.11.2018 14:58

Я использую библиотеку Moshi. Есть ли разница при использовании библиотеки Anko?

Rajesh 13.11.2018 05:30

Я думаю, проблема связана с библиотекой moshi. Я обновил ответ.

aminography 13.11.2018 06:45

Вы можете объяснить, почему возникла проблема с библиотекой moshi?

Rajesh 14.11.2018 06:28

Если вы добавляете библиотеку moshi вместо moshi-kotlin или не добавляете KotlinJsonAdapterFactory в конструктор moshi, он заполняет значение null в переменной модели json.

aminography 14.11.2018 06:46

Я все еще в замешательстве. Ошибка возникает при вызове метода createFromParcel для воссоздания объекта Parcelable.

Rajesh 14.11.2018 07:25

Хорошо, вы определили, что realtorImageUrl не является нулевым, и kotlin не позволяет установить его нулевым. Единственный возможный способ сделать это - установить нулевое значение путем отражения. Поскольку библиотеки json для обработки аннотаций устанавливают значения для полей с помощью отражения, проблема определенно исходит от них.

aminography 14.11.2018 07:35

Расскажите мне о двух моментах, о которых я сказал, пожалуйста (moshi-kotlin и KotlinJsonAdapterFactory). Вы их проверяли?

aminography 14.11.2018 07:37

Сэр, в чем проблема с решением, которое есть у OP, вот в чем вопрос.

azizbekian 14.11.2018 13:26

Это производственный код, который не воспроизводится, поэтому я не могу использовать другие решения moshi-kotlin и KotlinJsonAdapterFactory. Странная часть состоит в том, что у меня есть много моделей этого типа и я передаю их во фрагменте, но я получаю ошибку только в этой модели свойств.

Rajesh 16.11.2018 10:02

Согласно github.com/square/moshi#kotlin, это необходимо для правильной работы моши в котлине. Думаю, к сожалению, в описанной вами ситуации у нас нет выбора: - |

aminography 16.11.2018 10:15

Что ж, это может быть не идеальное решение, но оно может решить вашу проблему. Вы можете сделать свое свойство обнуляемым и просто добавлять нулевую проверку всякий раз, когда вы обращаетесь к ним.

Просто инициализируйте вашу переменную, как это

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)
    )
}

А в PropertyDetailsFragment.kt

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

Проблема не в недействительности property, проблема заключается в realtorImageUrl.

aminography 15.11.2018 17:48

Можете ли вы попробовать использовать @field: Json (name = "RealtorImageUrl") и проверить, работает ли он тогда?

Также проверьте, правильно ли вы добавили фабрику KotlinJsonAdapterFactory ()

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

Другие вопросы по теме