实际上在ListenerForSingleValueEvent

时间:2019-03-14 00:39:17

标签: firebase firebase-realtime-database kotlin

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

3 个答案:

答案 0 :(得分:1)

在您的情况下,val uri = userProfile?.image 运行userProfile = p0.getValue(Users::class.java)之前说明发生此问题的原因。

我认为有帮助

    低于code2
  • code1并不意味着它code2运行时之后运行。
  • “ Lateinit从未初始化”是运行时错误,当您尝试在运行时未初始化编译时间的变量时尝试使用该变量。
  • code1addListenerForSingleValueEvent

答案 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
    }
}