Firebase &引用;“Lateinit从未初始化”;而它实际上是在ListenerForSingleValueEvent中初始化的
在编辑2中更新了代码 编辑:Firebase &引用;“Lateinit从未初始化”;而它实际上是在ListenerForSingleValueEvent中初始化的,firebase,firebase-realtime-database,kotlin,Firebase,Firebase Realtime Database,Kotlin,在编辑2中更新了代码 编辑: 我发现我认为解决了同样的问题,但我很难理解这里到底发生了什么,因为它在Java中,我的Java不如我的kotlin。如有任何澄清,将不胜感激 每当我声明一个lateinit变量,然后从一个ListenerForSingleValueEvent初始化它时,我都会得到一个从未初始化过的错误。这就像初始化是受侦听器限制的。我最后做的是大量嵌套,但这会使代码非常混乱。这有什么原因吗?有办法绕过它吗 例如,在下面的代码中,我将得到一个错误,说明userProfile从未初始化
我发现我认为解决了同样的问题,但我很难理解这里到底发生了什么,因为它在Java中,我的Java不如我的kotlin。如有任何澄清,将不胜感激 每当我声明一个lateinit变量,然后从一个ListenerForSingleValueEvent初始化它时,我都会得到一个从未初始化过的错误。这就像初始化是受侦听器限制的。我最后做的是大量嵌套,但这会使代码非常混乱。这有什么原因吗?有办法绕过它吗 例如,在下面的代码中,我将得到一个错误,说明
userProfile
从未初始化:
class ProfileFragment : Fragment() {
lateinit var userProfile: Users
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_profile, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
arguments?.let {
val safeArgs = ProfileFragmentArgs.fromBundle(it)
val userProfileUid = safeArgs.usersProfile
val refUser = FirebaseDatabase.getInstance().getReference("users/$userProfileUid")
refUser.addListenerForSingleValueEvent(object : ValueEventListener{
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
userProfile = p0.getValue(Users::class.java)
}
})
}
val uri = userProfile?.image
Picasso.get().load(uri).into(profilePicture)
profileName.text = userProfile?.name
}
}
编辑2:
在阅读了Alex Mamo关于这个问题的答案和他所附的答案后,我试图相应地修改我的代码,但仍然无法正常工作
这是y当前代码(元素不同,因为我一直在编写代码,但情况完全相同)
*我尝试将cal for readData与arguments部分或之后放在一起,但这两种方法都不适用于我,并且我一直得到一个错误,即当我尝试在onViewCreated中使用imageObject时,imageObject未初始化
class ImageFullSizeFragment : androidx.fragment.app.Fragment() {
lateinit var refImage: DatabaseReference
lateinit var imageObject: Images
override fun onAttach(context: Context) {
super.onAttach(context)
arguments?.let {
val safeArgs = ImageFullSizeFragmentArgs.fromBundle(it)
val imageId = safeArgs.imageId
refImage = FirebaseDatabase.getInstance().getReference("/images/feed/$imageId")
readData(object : MyImageCallBack {
override fun onCallback(value: Images) {
imageObject = value
}
})
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mainImage = view.findViewById<ImageView>(R.id.image_full_image)
Picasso.get().load(Uri.parse(imageObject.image)).into(mainImage)
}
fun readData(myImagesCallback: MyImageCallBack) {
refImage.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
val image = p0.getValue(Images::class.java)
myImagesCallback.onCallback(image!!)
}
})
}
}
在您的例子中,
val uri=userProfile?.image
在userProfile=p0.getValue(Users::class.java)
之前运行
我觉得这有帮助
以下code2
并不意味着它code1
在code2
运行时运行李>code1
- “Lateinit从未初始化”是运行时错误,当您尝试使用未在运行时非编译时初始化的变量时发生
是addListenerForSingleValueEvent
asynonymous
onDataChange
时,userProfile
初始化。但在此之前,您可以访问userProfile
。因此,发生了未初始化的异常
解决方案
将setupview
移动到onDataChange
,尝试此代码
override fun onDataChange(p0: DataSnapshot) {
userProfile = p0.getValue(Users::class.java).also {
Picasso.get().load(it.image).into(profilePicture)
profileName.text = it.name
}
}
Firebase API是
异步的
,这意味着调用onDataChange()
函数后立即返回,它返回的任务
的回调将在稍后调用。无法保证需要多长时间。因此,在数据可用之前,可能需要几百毫秒到几秒钟的时间
因为该方法会立即返回,所以从数据库中获取并试图在回调外部使用的userProfile
对象的值还没有填充
基本上,您正在尝试同步使用来自异步API的值。那不是个好主意。您应该按照预期异步处理API。因此,在本例中,它与lateinit
无关
此问题的快速解决方法是移动以下代码行:
val uri = userProfile?.image
Picasso.get().load(uri).into(profilePicture)
profileName.text = userProfile?.name
并仅在回调中使用它们。通过这种方式,来自数据库的数据将可用
如果你想在回调之外使用它,我建议你看一下我的anwser的最后一部分,我已经解释了如何使用自定义回调。这是针对Cloud Firestore的,但同样的规则适用于Firebase实时数据库。谢谢,我假设如果它在它之后,那么它将在它之后运行。我会调查的。谢谢Alex,很抱歉回复晚了。我觉得我必须在回调之外使用它,因为我的片段承载着另一个片段,而子片段需要访问我从侦听器获得的对象。我看了你的另一个答案,看起来很清楚,很直截了当,但我肯定错过了什么,因为我无法让它发挥作用。介意告诉我我做错了什么吗?我用我的新代码添加了一个edit(元素不同,因为我一直在编写代码,但情况完全相同)。正如我看到的,您正在做与以前相同的事情。在
readData
函数中指定imageObject=value
并不意味着它将能够简单地在这一行Picasso.get().load(Uri.parse(imageObject.image)).into(mainImage)
中使用imageObject
的值。要解决此问题,请将该行移到函数readData
中或更改获取数据的逻辑。这就是异步编程的工作原理。很抱歉我来自澳大利亚,回复太晚了。哈哈。我将其标记为正确,因为它听起来是正确的,但我个人最终使用共享视图模型来传输数据。我感谢你的帮助!如果你也认为我的回答也会有助于未来的开发者,也请考虑投票表决。▲). 非常感谢,谢谢!
val uri = userProfile?.image
Picasso.get().load(uri).into(profilePicture)
profileName.text = userProfile?.name