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

Android Firebase无法下载图片至Bitmap数组及替代方案咨询

问题1:Bitmap数组为空的原因及解决方法

核心原因:异步执行顺序错误

你的代码中,bitmapArray.addAll(bitmapArray)、bitmapArray.shuffle()以及日志打印操作,都是在图片异步下载完成前执行的。getFile()是异步方法,addOnSuccessListener中的代码只有在图片下载完成后才会回调执行,此时bitmapArray还未添加任何元素,执行addAll后依然是空数组。

修复方案:等待所有异步任务完成后再处理数组

使用Firebase的Tasks.whenAll()合并两个下载任务,等两张图片都下载完成后,再执行数组复制、打乱操作:

upload.setOnClickListener(View.OnClickListener {
    // 每次点击清空数组,避免重复累积元素
    bitmapArray.clear()

    val task1 = try {
        val localfile = File.createTempFile("tempfile", ".jpg")
        aDatabase.getFile(localfile).addOnSuccessListener {
            val bitmap = BitmapFactory.decodeFile(localfile.absolutePath)
            bitmapArray.add(bitmap)
        }.addOnFailureListener {
            Log.w("myapplication", "ERROR RETRIEVING IMAGE 1")
            Toast.makeText(this, "ERROR RETRIEVING IMAGE 1", Toast.LENGTH_SHORT).show()
        }
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }

    val task2 = try {
        val localfile = File.createTempFile("tempfile1", ".jpg")
        sDatabase.getFile(localfile).addOnSuccessListener {
            val bitmap = BitmapFactory.decodeFile(localfile.absolutePath)
            bitmapArray.add(bitmap)
        }.addOnFailureListener {
            Log.w("myapplication", "ERROR RETRIEVING IMAGE 2")
            Toast.makeText(this, "ERROR RETRIEVING IMAGE 2", Toast.LENGTH_SHORT).show()
        }
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }

    // 等待两个下载任务都完成
    Tasks.whenAll(task1, task2).addOnSuccessListener {
        // 复制数组并打乱
        bitmapArray.addAll(bitmapArray)
        bitmapArray.shuffle()
        Log.w("myapplication", bitmapArray.size.toString()) // 此时输出应为4

        // 重置按钮点击逻辑,确保数组可用时再操作
        buttons.forEachIndexed { index, button ->
            button.tag = false // 标记卡片是否已翻转
            button.setOnClickListener {
                val isFlipped = button.tag as Boolean
                if (!isFlipped && bitmapArray.isNotEmpty()) {
                    button.setImageBitmap(bitmapArray[index])
                    button.tag = true
                } else {
                    // 切换回卡片背面图,需替换为你的背面资源ID
                    button.setImageResource(R.drawable.card_back)
                    button.tag = false
                }
            }
        }
    }.addOnFailureListener {
        Log.w("myapplication", "One or more download tasks failed")
    }
})
问题2:Firebase Storage获取图片的其他方法

除了下载到临时文件再解码,还有以下三种常用方式:

1. 直接获取字节数组解码为Bitmap

跳过临时文件,直接获取图片字节数组并解码:

// 设置最大下载字节数,示例为10MB
val maxSize = 10L * 1024 * 1024
aDatabase.getBytes(maxSize).addOnSuccessListener { bytes ->
    val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
    // 使用bitmap更新UI或存入数组
}.addOnFailureListener {
    Log.w("myapplication", "Failed to get image bytes")
}

2. 使用图片加载库(推荐)

用Glide或Picasso这类成熟库,自动处理异步加载、缓存和内存管理,直接加载Firebase Storage引用:

Glide示例(需先添加依赖)

// 模块级build.gradle添加依赖
// implementation 'com.github.bumptech.glide:glide:4.16.0'
// annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'

Glide.with(this)
    .load(aDatabase) // 直接传入FirebaseStorage的Reference
    .into(button1) // 加载到目标ImageButton

Picasso示例

// 添加依赖:implementation 'com.squareup.picasso:picasso:2.71828'

Picasso.get()
    .load(aDatabase)
    .into(button1)

3. 获取下载URL后加载

如果需要将URL存入实时数据库,正确的获取和使用方式如下:

获取并存储下载URL

aDatabase.downloadUrl.addOnSuccessListener { uri ->
    val fullImageUrl = uri.toString()
    // 将URL存入实时数据库
    FirebaseDatabase.getInstance().getReference("gameImages/image1").setValue(fullImageUrl)
}.addOnFailureListener {
    Log.w("myapplication", "Failed to get download URL")
}

从数据库读取URL并加载

FirebaseDatabase.getInstance().getReference("gameImages/image1")
    .addListenerForSingleValueEvent(object : ValueEventListener {
        override fun onDataChange(snapshot: DataSnapshot) {
            val imageUrl = snapshot.getValue(String::class.java) ?: return
            // 用Glide加载
            Glide.with(this@game2x2)
                .load(imageUrl)
                .into(button1)
            // 或手动解码(需在子线程执行)
            Thread {
                val bitmap = BitmapFactory.decodeStream(URL(imageUrl).openStream())
                runOnUiThread { button1.setImageBitmap(bitmap) }
            }.start()
        }

        override fun onCancelled(error: DatabaseError) {
            Log.w("myapplication", "Failed to read image URL from database")
        }
    })

你之前尝试存访问令牌失败,大概率是没有获取完整的下载URL,而是只存储了令牌片段。通过downloadUrl获取的URI包含完整的访问参数,可直接用于加载图片。

内容的提问来源于stack exchange,提问作者Berk Sunduri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 11:31:12