"Lateinit从未初始化".虽然它实际上是在ListenerForSingleValueEvent内部初始化的 [英] "Lateinit was never initialized" while it is actually initialized inside a ListenerForSingleValueEvent

查看:117
本文介绍了"Lateinit从未初始化".虽然它实际上是在ListenerForSingleValueEvent内部初始化的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑2中的更新代码

修改:
我发现了,我认为这解决了同样的问题,但是我很难理解这里到底发生了什么,就像Java中发生的一样,我的Java不如我的Kotlin好.任何澄清将不胜感激.


I've found this which I think addresses the same issue but I'm having a hard time understanding exactly what's happening here as it's in Java and my Java is not as good as my kotlin. Any clarification would be appreciated.

每当我声明一个Lateinit变量,然后从ListenerForSingleValueEvent对其进行初始化时,都会收到一个错误,即它从未被初始化.就像初始化受侦听器限制一样.我最终要做的是大量的嵌套,但是这使代码非常混乱.有什么理由吗?可以解决吗?

Whenever I declare a lateinit variable and then initialize it from a ListenerForSingleValueEvent, I get an error that it was never initialized. It's like the initialization is bounded by the listener. What I end up doing is a lot of nesting, but it makes the code very messy. Is there a reason for that? A way around it?

例如,在下面的代码中,我将得到一条错误消息,指出从未初始化userProfile:

For example, in this following code I will get an error saying that userProfile was never initialized:

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


    }
}

在阅读了Alex Mamo对此问题以及他所附加问题的回答后,我试图相应地更改我的代码,但仍然无法使其正常工作.

After reading Alex Mamo's answer on this Q and the one he attached, I have tried to change my code accordingly but still can't make it to work.

这是您当前的代码(这些元素与我编写代码时有所不同,但是大小写完全相同)

Here's y current code (the elements are different as I've been working on my code but it's exactly the same case)

*我尝试将readData的cal放在参数部分或之后,但对我都不起作用,当我在onViewCreated中尝试使用imageObject时,我一直收到以下错误:未初始化imageObject

*I've tried placing the cal for readData with the arguments section or after but neither work for me and I keep getting the error that imageObject wasn't initialized when I try to use it in the onViewCreated

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)
}

推荐答案

Firebase API是asynchronous,这意味着onDataChange()函数在调用后立即返回,并且将调用从它返回的Task中的回调.一段时间以后.无法保证需要多长时间.因此,可能需要几百毫秒到几秒钟的时间才能获得该数据.

Firebase APIs are asynchronous, meaning that onDataChange() function returns immediately after it's invoked, and the callback from the Task it returns, will be called some time later. There are no guarantees about how long it will take. So it may take from a few hundred milliseconds to a few seconds before that data is available.

因为该方法会立即返回,所以尚未填充从数据库中获取的userProfile对象的值,并且您试图在回调之外使用它.

Because that method returns immediately, the value of your userProfile object that you are getting from the database and you're trying to use it outside the callback, will not have been populated yet.

基本上,您正在尝试从异步的API同步使用一个值.那不是一个好主意.您应该按预期异步处理API.因此,在这种情况下,它与lateinit没有任何关系.

Basically, you're trying to use a value synchronously from an API that's asynchronous. That's not a good idea. You should handle the APIs asynchronously as intended. So, in this case it has nothing to do with the lateinit.

对此问题的快速解决方案是移动以下代码行:

A quick solve for this problem would be to move the following lines of code:

val uri = userProfile?.image
Picasso.get().load(uri).into(profilePicture)
profileName.text = userProfile?.name

并在回调中仅使用它们.这样,来自数据库的数据将可用.

And use them only inside the callback. In this way the data that it comes from the database will be available.

如果您想在回调之外使用它,建议您从此

If you want to use it outside tha callback, I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. It's for Cloud Firestore but same rules apply in case of Firebase realtime database.

这篇关于"Lateinit从未初始化".虽然它实际上是在ListenerForSingleValueEvent内部初始化的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆