Kotlin - 非空参数为空引发IllegalArgumentException异常

5
我将数据通过Bundle传递给某个片段,在接收时出现异常。这个错误发生在恢复片段状态时。
当调用createFromParcel时,在非空的Model字段中发生异常,会在Intrinsics.checkParameterIsNotNull中出现错误。
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扩展插件提供了@Parcelize注解,用于生成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 {
            putParcelable(INT_EXTRA_PROPERTY, property)
        }
    }
    ...
}

我需要怎么做才能解决这个问题?

1
@EpicPandaForce 我的意思是说当数据被显示时它不是空的。我想知道它为什么会变成空的原因。 - Rajesh Jadav
  1. 你如何定义 realtorImageUrl
  2. 你如何与 realtorImageUrl 进行交互?在哪个方法(或重写方法)中?
- ariefbayu
请发布与“realtorImageUrl”交互以及如何从可包含对象中设置/检索它的代码。 - Eric Martori
@ariefbayu 我已经添加了更多细节。 - Rajesh Jadav
1
问题可能出在Json解析上,每当JsonResponse没有RealtorImageUrl时,它会将其视为null。 - Lalit Jadav
显示剩余8条评论
3个回答

3
由于realtorImageUrl已被定义为非空,因此kotlin不允许将其设置为空。因此,唯一可能的方法是通过反射设置空值。Json帮助库基于注释处理,并使用反射将值设置到字段中,因此问题肯定来自它们。
  • 首先,我强烈建议您使用Google的Gson
  • 其次,请确保在配置更改后json字符串不为空。
  • 第三,请确保您在依赖项中使用moshi-kotlin(而不是简单的moshi),并向moshi构建器添加KotlinJsonAdapterFactory的实例。

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

在为片段提供参数时,最好使用来自AnkowithArguments

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
我正在使用Moshi库。使用Anko库有什么区别吗? - Rajesh Jadav
我认为问题出在moshi库。我已经更新了答案。 - aminography
如果您在Moshi构建器中添加了moshi库而不是moshi-kotlin,或者没有添加KotlinJsonAdapterFactory,则它会将null填充到JSON模型变量中。 - aminography
1
好的,你已经定义了 realtorImageUrl 不为空,并且 Kotlin 不允许将其设置为 null。唯一可能的方法是通过反射设置 null 值。由于注解处理器 JSON 库使用反射将值设置到字段中,所以问题肯定来自它们。 - aminography
显示剩余6条评论

0

嗯,这可能不是完美的解决方案,但它可以解决您的问题。您可以使属性可为空,并在访问它们时添加空值检查。

只需像这样初始化您的变量

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

0

你可以尝试使用 @field:Json(name = "RealtorImageUrl"),然后检查它是否有效吗?

另外,请检查是否已添加适当的 KotlinJsonAdapterFactory() 工厂。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接