编辑2中的更新代码
修改:
我发现this可以解决相同的问题,但是我很难确切地了解这里发生的情况以及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对此问题以及他所附加问题的回答之后,我试图相应地更改我的代码,但仍然无法使其正常工作。
这是您当前的代码(这些元素与我编写代码时有所不同,但情况完全相同)
*我尝试将readData的cal放在参数部分或之后,但对我都不起作用,当在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!!)
}
})
}
}
这是接口:
interface MyImageCallBack {
fun onCallback(value: Images)
}
答案 0 :(得分:1)
在您的情况下,val uri = userProfile?.image
运行在userProfile = p0.getValue(Users::class.java)
之前说明发生此问题的原因。
我认为有帮助
code2
的code1
并不意味着它code2
在运行时之后运行。 code1
是addListenerForSingleValueEvent
答案 1 :(得分:1)
Firebase API为asynchronous
,这意味着onDataChange()
函数在被调用后立即返回,而从其返回的Task
的回调将在一段时间后被调用。无法保证需要多长时间。因此,可能需要几百毫秒到几秒钟的时间才能获得该数据。
由于该方法会立即返回,因此尚未填充从数据库中获取的userProfile
对象的值,并且您试图在回调之外使用它。
基本上,您正在尝试从异步的API同步使用值。那不是一个好主意。您应该按预期异步处理API。因此,在这种情况下,它与lateinit
无关。
对此问题的快速解决方案是移动以下代码行:
val uri = userProfile?.image
Picasso.get().load(uri).into(profilePicture)
profileName.text = userProfile?.name
并在回调中仅仅使用它们。这样,来自数据库的数据将可用。
如果您想在回调之外使用它,建议您从此 post 中查看anwser的最后一部分,其中我已经解释了如何使用自定义功能打回来。它用于Cloud Firestore,但对于Firebase实时数据库,适用相同的规则。
答案 2 :(得分:0)
例如,在下面的代码中,我将收到一条错误消息,指出userProfile从未初始化。
调用onDataChange
时,将初始化userProfile
。但在此之前,您访问userProfile
。因此,发生了未初始化的异常。
将setupViews
移至onDataChange
,尝试使用此代码
override fun onDataChange(p0: DataSnapshot) {
userProfile = p0.getValue(Users::class.java).also {
Picasso.get().load(it.image).into(profilePicture)
profileName.text = it.name
}
}