Lateinit 属性未在 Fragment 上初始化

Lateinit properties were not initialized on Fragment

我已经编写了我的第一个 Kotlin 和 android 应用程序,但我在这个应用程序上遇到了很多崩溃。

所有这些都与lateinit关键字相关。

我遇到的崩溃情况如下:

Caused by e.y: lateinit property coordinator has not been initialized

和:

Fatal Exception: java.lang.RuntimeException
Unable to start activity ComponentInfo{app.myapp/mypackage.myapp.Controllers.MainActivity}: e.y: lateinit property coordinator has not been initialized

Caused by e.y
lateinit property coordinator has not been initialized
myapp.com.myapp.Controllers.Fragments.Parents.MyParentFragment.getCoordinator


例如,最后一个跟踪与我在片段上设置的变量有关,一旦我像这样初始化它:

        fun newInstance(mainObject: MyObject, anotherObject: AnotherObject, coordinator: FragmentCoordinator): MyFragment {
            val fragment = MyFragment()
            fragment.mainObject = mainObject
            fragment.anotherObject = ticket
            fragment.coordinator = coordinator
            return fragment
        }

片段边看起来像:

class MyFragment: MyParentFragment() {

     companion object {
        fun newInstance(mainObject:...)
     }

    lateinit var mainObject: MainObject
    lateinit var anotherObject: AnotherObject
    ... 
}

据我了解,当应用程序更改其状态(背景...)时,此 lateinit 属性引用会丢失,一旦调用此变量的代码 属性 为空并且应用程序崩溃...请理解一旦创建了片段,所有这些变量都不为空,它们就会被分配。

我找到了这篇文章:https://www.bignerdranch.com/blog/kotlin-when-to-use-lazy-or-lateinit/ 表明发生了什么,可以使用 by lifecycleAwareLazy(lifecycle) 将变量链接到应用程序生命周期来修复他添加的文章末尾的内容:这两个属性 代表解决了一个问题,但没有完全解决。 它们仍然包含内存泄漏。他为什么说 "they still contains memory leaks ?"

那么如何 android 我可以确定无论应用程序从后台返回还是其他原因,我的变量总是被设置,因为当应用程序显示片段时会发生这种情况,一些代码 运行 很好,然后需要调用这个 lateinit 变量并崩溃,因为这个变量不再存在,但一旦创建片段就存在。

感谢您的帮助。

lateinit 表示您没有在声明时分配变量值,但您必须在使用它之前在 java class 后期分配该值。

如果您尝试在赋值之前获取 lateinit 变量的值,则会发生 lateinit property coordinator has not been initialized 异常。

如果您不确定您的 lateinit varibale 是否已分配,您可以使用检查值 isInitialized 为 lateinit 变量提供的方法以避免崩溃。

示例:

if(::varibleName.isInitialized){
// do something
}

如果要在配置更改后保存变量值,则必须使用 ViewModel

如果您不使用 ViewModel 而不是通过 bundle 传递值并从中再次获取值并重新分配变量,但请注意,如果您使用 bundle 传递的值过多,您将获得 TooLargeTransition 异常。您还可以使用 onSaveInstanceState 来存储更新的值并在 onCreate 方法中检索它。

当您的 activity 被重新创建时,FragmentManager 调用每个附加的 Fragment 的 0 参数构造函数来重新创建它们。

您的 newInstance 方法应该只创建一个 Bundle 并在 Fragment.setArguments(Bundle) 中使用它,因为这是确保这些参数在配置更改后仍然存在的唯一方法。然后在 onCreate 中,您可以 getArguments 检索 Bundle.

如果您需要无法放入 Bundle 的参数,您必须在 Fragments onCreate 或其他方法中注入/重新创建/获取它们。

    fun newInstance(mainObject: MyObject, anotherObject: AnotherObject, coordinator: FragmentCoordinator): MyFragment {
        val fragment = MyFragment()
        fragment.mainObject = mainObject
        fragment.anotherObject = ticket
        fragment.coordinator = coordinator
        return fragment
    }

不能这样创建Fragment,不能这样设置字段变量。

系统在内存不足的情况下通过反射使用no-arg构造函数重新创建片段。你的代码,在这里,newInstance 和东西 - 永远不会运行。从来没有。

另一方面,setArguments(Bundle 参数由系统保留,您可以使用 getArguments().

获取它们

所以目前,如果您的应用程序被置于后台,被 Android 杀死,然后您再次从启动器打开该应用程序,那么您将会崩溃。

查看相关问题:

  • (我在这里描述了如何在开发环境中轻松重现它)

  • 也可能