Я передаю данные некоторому фрагменту в связке, и при его получении выдается исключение. Эта ошибка возникает при восстановлении состояния фрагмента.
Ошибка возникает в 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)
}
}
...
}
Что мне нужно сделать, чтобы исправить проблему?
Нет, ты не можешь быть уверен. ошибка заключается в том, что ваш realtorImageUrl, который вы указали как ненулевое, по какой-то причине получает значение null. вы могли бы принять его как lateinit var, который все еще не инициализирован при доступе.
@NileshRathod Ссылка, которую вы предоставили, - это другая проблема. При доступе к java-классам в kotlin все переменные равны нулю, поэтому вам нужно использовать "?" при доступе к любой переменной java. Я не знаю, как параметр в модели получил значение null.
Вы говорите I know realtorImageUrl is not null, но ясно, что он может быть нулевым.
@EpicPandaForce Я хочу сказать, что данные не являются нулевыми, когда они отображаются. Я хочу знать причину, по которой он стал нулевым.
1) как вы определяете realtorImageUrl? 2) как вы взаимодействуете с realtorImageUrl? в каком методе (или методе переопределения)?
Пожалуйста, опубликуйте код о том, как вы взаимодействуете с realtorImageUrl и как вы устанавливаете / извлекаете его из посылки.
@ariefbayu Я добавил подробностей.
@EricMartori Я добавил больше деталей.
Проверяли ли вы, что Property правильно настроен и что realtorImageUrl не равен нулю, прежде чем добавлять его в качестве дополнительного свойства? Кажется, что вы получаете в нем нулевое значение, которое с вашими определениями могло произойти только при создании экземпляра Property.
Как вы звоните showPropertyDetails(property: Property)? Вполне возможно, что showPropertyDetails() вызывается до установки property / realtorImageUrl. Это проблема lateinit, вы должны убедиться, что переменная уже установлена и установлена в правильном порядке.
Вы пытались установить свойство как допускающее значение NULL - val realtorImageUrl: String??
Проблема может быть в парсинге Json, всякий раз, когда JsonResponse не имеет RealtorImageUrl, он будет рассматривать его как null
Поскольку realtorImageUrl определен как ненулевой, поэтому kotlin не позволяет установить его как null. Поэтому единственный возможный способ сделать это - установить нулевое значение путем отражения. Вспомогательные библиотеки Json основаны на обработке аннотаций и использовании отражения для установки значений в поля, поэтому проблема определенно исходит от них.
Gson.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, и никаких проблем с восстановлением состояния фрагмента, например поворота телефона, не возникло.
Я использую библиотеку Moshi. Есть ли разница при использовании библиотеки Anko?
Я думаю, проблема связана с библиотекой moshi. Я обновил ответ.
Вы можете объяснить, почему возникла проблема с библиотекой moshi?
Если вы добавляете библиотеку moshi вместо moshi-kotlin или не добавляете KotlinJsonAdapterFactory в конструктор moshi, он заполняет значение null в переменной модели json.
Я все еще в замешательстве. Ошибка возникает при вызове метода createFromParcel для воссоздания объекта Parcelable.
Хорошо, вы определили, что realtorImageUrl не является нулевым, и kotlin не позволяет установить его нулевым. Единственный возможный способ сделать это - установить нулевое значение путем отражения. Поскольку библиотеки json для обработки аннотаций устанавливают значения для полей с помощью отражения, проблема определенно исходит от них.
Расскажите мне о двух моментах, о которых я сказал, пожалуйста (moshi-kotlin и KotlinJsonAdapterFactory). Вы их проверяли?
Сэр, в чем проблема с решением, которое есть у OP, вот в чем вопрос.
Это производственный код, который не воспроизводится, поэтому я не могу использовать другие решения moshi-kotlin и KotlinJsonAdapterFactory. Странная часть состоит в том, что у меня есть много моделей этого типа и я передаю их во фрагменте, но я получаю ошибку только в этой модели свойств.
Согласно github.com/square/moshi#kotlin, это необходимо для правильной работы моши в котлине. Думаю, к сожалению, в описанной вами ситуации у нас нет выбора: - |
Что ж, это может быть не идеальное решение, но оно может решить вашу проблему. Вы можете сделать свое свойство обнуляемым и просто добавлять нулевую проверку всякий раз, когда вы обращаетесь к ним.
Просто инициализируйте вашу переменную, как это
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.
Можете ли вы попробовать использовать @field: Json (name = "RealtorImageUrl") и проверить, работает ли он тогда?
Также проверьте, правильно ли вы добавили фабрику KotlinJsonAdapterFactory ()
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()