You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase实时数据库子路径值展示及imageURL跨函数取值异常求助

Firebase相关问题解答

问题2:Firebase Storage上传后外部获取imageURL为null的问题

原因分析

Firebase Storage的putBytes是异步操作,代码执行时,调用saveQrCodeToStorage后不会等待上传完成,就立刻执行后续创建DataClass和写入数据库的逻辑。此时addOnSuccessListener里的imageURL赋值还未执行,所以外部访问时imageURL仍是初始的null。

解决方案

把数据库写入逻辑移到saveQrCodeToStorage的addOnSuccessListener回调内部,确保只有上传完成、imageURL赋值成功后,再执行数据入库操作。同时修复代码中重复定义NewTraceabilityActivity的问题,修改后的核心代码如下:

class NewTraceabilityActivity : AppCompatActivity() {
    private lateinit var binding : ActivityNewTraceabilityBinding
    private lateinit var firebaseAuth : FirebaseAuth
    private lateinit var firebaseref : DatabaseReference
    var uri : Uri? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityNewTraceabilityBinding.inflate(layoutInflater)
        setContentView(binding.root)

        firebaseAuth = FirebaseAuth.getInstance()
        firebaseref = FirebaseDatabase.getInstance().getReference("Product")

        binding.closeBtn.setOnClickListener {
            finish()
        }

        binding.createTraceabilityBtn.setOnClickListener {
            saveData()
        }
    }

    @SuppressLint("SuspiciousIndentation")
    private fun saveData(){
        uploadData()
        // 注意:dialog变量未在代码中定义,需确保已初始化后再调用dismiss()
        // dialog.dismiss()
    }

    private fun uploadData(){
        val newProductID = firebaseref.push()
        val pid = newProductID.key!!

        val farmer = binding.farmerEt.text.toString()
        val variety = binding.varietytEt.text.toString()
        val weight = binding.weightEt.text.toString()
        val currentDate = DateFormat.getDateTimeInstance().format(Calendar.getInstance().time)

        val qrCodeBitMap = generateQrCode(pid)
        saveQrCodeToStorage(pid, qrCodeBitMap, object : QrUploadCallback {
            override fun onSuccess(imageUrl: String) {
                // 上传成功后才创建DataClass并写入数据库
                val dataClass = DataClass(pid, farmer, variety, weight, currentDate, imageUrl)
                FirebaseDatabase.getInstance().getReference("users")
                    .child(firebaseAuth.uid.toString())
                    .child("pid")
                    .child(pid)
                    .setValue(dataClass)
                    .addOnCompleteListener { task ->
                        if (task.isSuccessful){
                            Toast.makeText(this@NewTraceabilityActivity, "Created", Toast.LENGTH_SHORT).show()
                            Toast.makeText(this@NewTraceabilityActivity, "get $pid successfully from firebase", Toast.LENGTH_SHORT).show()
                            startActivity(Intent(this@NewTraceabilityActivity, TraceabilityListActivity::class.java))
                            finish()
                        }
                    }
                    .addOnFailureListener { e ->
                        Toast.makeText(this@NewTraceabilityActivity, e.message.toString(), Toast.LENGTH_SHORT).show()
                    }
            }

            override fun onFailure(errorMsg: String) {
                Toast.makeText(this@NewTraceabilityActivity, errorMsg, Toast.LENGTH_SHORT).show()
            }
        })
    }

    // 定义回调接口,传递上传结果
    interface QrUploadCallback {
        fun onSuccess(imageUrl: String)
        fun onFailure(errorMsg: String)
    }

    private fun saveQrCodeToStorage(pid: String, qrCodeBitmap: Bitmap, callback: QrUploadCallback) {
        val storage = FirebaseStorage.getInstance()
        val storageRef = storage.reference
        val qrCodeRef: StorageReference = storageRef.child("qr_codes/$pid.jpg")

        val baos = ByteArrayOutputStream()
        qrCodeBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
        val data: ByteArray = baos.toByteArray()

        qrCodeRef.putBytes(data)
            .addOnSuccessListener { taskSnapshot ->
                taskSnapshot.storage.downloadUrl.addOnSuccessListener { urlImage ->
                    val imageUrl = urlImage.toString()
                    callback.onSuccess(imageUrl)
                    Log.i("QrCode", "Success upload photo to storage firebase")
                }
            }
            .addOnFailureListener { exception ->
                val errorMsg = "something wrong with save qrCode to firebase: ${exception.message}"
                Log.e("QrCode", errorMsg)
                callback.onFailure(errorMsg)
            }
    }
}

问题1:如何在Firebase实时数据库中展示子路径的值?

以你代码中的入库路径users/{uid}/pid/{pid}为例,可通过以下步骤实现数据展示:

  1. 定位到目标子路径的DatabaseReference
  2. 添加数据监听,解析数据后更新UI

示例代码:

// 替换为实际的用户ID和产品ID
val uid = firebaseAuth.uid.toString()
val targetPid = "your_target_pid"

FirebaseDatabase.getInstance()
    .getReference("users")
    .child(uid)
    .child("pid")
    .child(targetPid)
    .addListenerForSingleValueEvent(object : ValueEventListener {
        override fun onDataChange(snapshot: DataSnapshot) {
            // 从快照中解析数据
            val dataClass = snapshot.getValue(DataClass::class.java)
            dataClass?.let {
                // 更新UI展示
                binding.farmerEt.setText(it.dataFarmer)
                binding.varietytEt.setText(it.dataVariety)
                binding.weightEt.setText(it.dataWeight)
                // 若需展示二维码,可使用图片加载库(如Glide)加载it.dataQrCode
            }
        }

        override fun onCancelled(error: DatabaseError) {
            Log.e("Database", "获取数据失败: ${error.message}")
            Toast.makeText(this@NewTraceabilityActivity, "获取数据失败", Toast.LENGTH_SHORT).show()
        }
    })

说明:

  • addListenerForSingleValueEvent仅获取一次数据,适合一次性展示需求
  • 若需实时监听数据变化,改用addValueEventListener,但需在页面销毁时调用removeEventListener避免内存泄漏

内容的提问来源于stack exchange,提问作者Harris AM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 06:54:54