[英]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: 查看相关问题:
Singleton object becomes null after app is resumed (where I describe how you can reproduce this in dev environment easily) 恢复应用程序后,Singleton对象变为空 (我描述了如何在开发环境中轻松重现此对象)
also maybe App crash after activity has been killed in background 也可能是活动在后台被杀死后应用崩溃
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.