简体   繁体   English

Lateinit属性未在Fragment上初始化

[英]Lateinit properties were not initialized on Fragment

I have write my first Kotlin and android app and i'm facing a lot of crashes on this app. 我已经写了我的第一个Kotlin和android应用程序,并且在此应用程序上我面临很多崩溃。

All of them are related to the lateinit keyword. 它们都与lateinit关键字相关。

i get crashes like : 我会崩溃:

Caused by ey: lateinit property coordinator has not been initialized

and: 和:

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


Last one trace for example is related to a variable i set on my fragment once i initialize it like this : 例如,最后一条跟踪与我在这样初始化它后在片段上设置的变量有关:

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

Fragment side looks like : 片段侧看起来像:

class MyFragment: MyParentFragment() {

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

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

What i understand is that when app changes its state (background...) this lateinit properties reference get lost, once the code call this variable property is null and app crash... Please understand that once they fragment is created all this variable are not null, they get allocated. 我了解的是,当应用程序更改其状态(背景...)时,此Lateinit属性引用会丢失,一旦代码调用此变量属性为null并导致应用程序崩溃...请理解,一旦它们创建碎片,所有此变量都是不为null,则会分配它们。

i have found this article : https://www.bignerdranch.com/blog/kotlin-when-to-use-lazy-or-lateinit/ which indicates what happened and can be fixed linking the variable to the app lifecycle using by lifecycleAwareLazy(lifecycle) thing is at the ends of the article he adds: These two property delegates solve one problem, but not completely. 我发现这篇文章: https://www.bignerdranch.com/blog/kotlin-when-to-use-lazy-or-lateinit/这表明发生了什么,可以固定使用变量链接到应用程序的生命周期by lifecycleAwareLazy(lifecycle)是他在文章结尾处添加的内容:这两个属性委托解决了一个问题,但并不完全。 They still contain a memory leak. 它们仍然包含内存泄漏。 Why does he says "they still contains memory leaks ?" 他为什么说“它们仍然包含内存泄漏?”

So how on android i can be sure that my variable always be set wether the app comes back from background or whatever, because this happen when the fragment is displayed by the app, some codes run good and then needs to call this lateinit variable and crash because this variable does not exist anymore but existed once the fragment where create. 因此,如何在android上确保我的变量始终设置为从应用程序从后台返回还是其他原因,因为这种情况发生在应用程序显示片段时,某些代码运行良好,然后需要调用此lateinit变量并崩溃因为此变量已不存在,但曾经在创建片段时存在。

Thank you for any help. 感谢您的任何帮助。

When your activity gets recreated, FragmentManager invokes 0-argument constructor of each attached Fragment to recreate them as well. 重新创建您的活动时, FragmentManager调用每个附加Fragment 0参数构造函数来重新创建它们。

Your newInstance method should only create a Bundle and use it in Fragment.setArguments(Bundle) as this is the only way to ensure those arguments survive configuration changes. 您的newInstance方法应该只创建一个Bundle并在Fragment.setArguments(Bundle)使用它,因为这是确保这些参数在配置更改后仍然有效的唯一方法。 Then inside onCreate you can getArguments to retrieve that Bundle . 然后在onCreate您可以getArguments检索该Bundle

If you need arguments that cannot be put in a Bundle , you have to inject / recreate / fetch them inside Fragments onCreate or other method. 如果需要不能放在Bundle参数,则必须在Fragments onCreate或其他方法中注入/重新创建/获取它们。

lateinit indicates that you are not assign the variable value at declaration time but you have to assign the value late in your java class before uses it. lateinit表示您没有在声明时分配变量值,但必须在使用Java类之前在lateinit分配值。

If you tries to get the value of lateinit variable before assignment than lateinit property coordinator has not been initialized exception is occur. 如果您尝试在赋值之前获取lateinit变量的值,而lateinit property coordinator has not been initialized则会发生异常。

If you are not sure that you lateinit varibale is assign or not you can check the value using isInitialized method given for lateinit variable to avoid crashes. 如果不确定是否分配了Lateinit varibale,则可以使用为lateinit变量指定的isInitialized方法检查该值,以避免崩溃。

Example : 范例:

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

If you want to save the variables values after configuration changes you have to use ViewModel . 如果要在配置更改后保存变量值,则必须使用ViewModel

If you not uses ViewModel than pass the values by bundle and get the values again from it and re-assign the variables, but note that if you are passing too many values using bundle than you will get the TooLargeTransition exception. 如果您不使用ViewModel而不是通过捆绑包传递值,然后再次从中获取值并重新分配变量,但是请注意,如果使用捆绑包传递的值太多,则会获得TooLargeTransition异常。 You can also used onSaveInstanceState to store the updated values and retrieve it in onCreate method. 您还可以使用onSaveInstanceState来存储更新的值,并在onCreate方法中对其进行检索。

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

You cannot create a Fragment like this, you cannot set field variables like this. 您不能像这样创建一个Fragment,也不能像这样设置字段变量。

The system recreates fragments after low memory condition using no-arg constructor via reflection. 系统在内存不足后使用no-arg构造函数通过反射重新创建片段。 Your code, here, newInstance and stuff - that never runs. 您的代码,这里的newInstance和其他内容-永远不会运行。 Never. 决不。

On another hand, setArguments(Bundle arguments are retained by the system, and you would be able to get them using getArguments() . 另一方面, setArguments(Bundle参数由系统保留,您可以使用getArguments()获取它们。

So currently, if your app is put to background, killed by Android, and you open the app from launcher again, then you'll crash. 因此,当前,如果您的应用程序被置于后台,被Android杀死,然后再次从启动器中打开该应用程序,则可能会崩溃。

See related questions: 查看相关问题:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM