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}为例,可通过以下步骤实现数据展示:
- 定位到目标子路径的
DatabaseReference - 添加数据监听,解析数据后更新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
相关产品推荐
相关产品推荐

