kotlin Android Firebase无法下载图像并将其添加到位图数组

hfyxw5xn  于 2022-12-19  发布在  Kotlin
关注(0)|答案(1)|浏览(101)

我目前正在制作一个匹配的纸牌游戏,我需要在Firebase上存储图像。我在启动游戏时通过按钮点击上传图像(这样做会自动产生同样的问题,但按钮一个更安全)我认为图像下载速度不够快,无法显示在卡面上,或者它可能无法与整个应用程序一起工作,因此位图数组内部的元素为零。我的当前代码是:

class game2x2 : AppCompatActivity() {
    private lateinit var database: DatabaseReference
    private lateinit var buttons: List<ImageButton>
    //private lateinit var bitmapArray: ArrayList<Bitmap>
    private var bitmapArray = mutableListOf<Bitmap>()
    private lateinit var button1: ImageButton
    private lateinit var button2: ImageButton
    private lateinit var button3: ImageButton
    private lateinit var button4: ImageButton
    private lateinit var upload: Button
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_game2x2)

        val min = 1
        val max = 45
        val database = FirebaseDatabase.getInstance()
        val imageID1 = Random().nextInt(max - min + 1) + min
        val imageID2 = Random().nextInt(max - min + 1) + min
        val aDatabase = FirebaseStorage.getInstance().getReference("all/$imageID1.jpg")
        val sDatabase = FirebaseStorage.getInstance().getReference("all/$imageID2.jpg")

        upload = findViewById(R.id.uploadButton)
        button1 = findViewById(R.id.imageButton1)
        button2 = findViewById(R.id.imageButton2)
        button3 = findViewById(R.id.imageButton3)
        button4 = findViewById(R.id.imageButton4)
        buttons = listOf(button1, button2, button3, button4)

        upload.setOnClickListener(View.OnClickListener {
            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")
                    Toast.makeText(this, "ERROR RETRIEVING IMAGE", Toast.LENGTH_SHORT).show()
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }

            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")
                    Toast.makeText(this, "ERROR RETRIEVING IMAGE", Toast.LENGTH_SHORT).show()
                }
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
            ///    DUPLICATE
            bitmapArray.addAll(bitmapArray)
            ///SHUFFLE
            bitmapArray.shuffle()
            Log.w("myapplication", bitmapArray.size.toString())
        })

        buttons.forEachIndexed { index, button ->
            button.setOnClickListener(View.OnClickListener {
                button.setImageBitmap(bitmapArray[index])
            })
        }
    }
}

除了下载图像并将其添加到临时文件,然后将其解码为位图之外,是否还有其他方法可以从Firebase存储中检索图像?
我尝试了任何我能找到的东西。我甚至尝试将图像的访问令牌添加到实时数据库中,然后从那里获取它们,但我失败得很惨。提前感谢您的帮助!

7tofc5zh

7tofc5zh1#

由于getFile()是一个异步任务,我可以想象您的日志语句Log.w("myapplication", bitmapArray.size.toString())正在执行,而bitmapArray仍然为空?这是因为aDatabase.getFile().addOnSuccessListener {}sDatabase.getFile().addOnSuccessListener {}在下载完成之前不会执行,但允许函数的其余部分继续执行。
您需要做的是等待下载结果,然后再继续复制和随机播放部分。
getFile()返回一个FileDownloadTask,它继承自StorageTaskStorageTask有一个isComplete()方法--还有一些其他的方法可能对错误情况有用。一个选择是在变量中捕获FileDownloadTask,并且在下载完成之前不继续执行。但是,要注意,这可能会冻结主线程。
编辑:你可以尝试禁用按钮,直到图像准备就绪,而不是检查主线程的状态。查看编辑评论:

class game2x2 : AppCompatActivity() {
    private lateinit var database: DatabaseReference
    private lateinit var buttons: List<ImageButton>
    //private lateinit var bitmapArray: ArrayList<Bitmap>
    private var bitmapArray = mutableListOf<Bitmap>()
    private lateinit var button1: ImageButton
    private lateinit var button2: ImageButton
    private lateinit var button3: ImageButton
    private lateinit var button4: ImageButton

    private val numImages = 2 // EDIT total number of images we need to download
    private val numImagesReady = AtomicInteger(0) // EDIT count of how many images are currently ready

    private lateinit var upload: Button
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_game2x2)

        val min = 1
        val max = 45
        val database = FirebaseDatabase.getInstance()
        val imageID1 = Random().nextInt(max - min + 1) + min
        val imageID2 = Random().nextInt(max - min + 1) + min
        val aDatabase = FirebaseStorage.getInstance().getReference("all/$imageID1.jpg")
        val sDatabase = FirebaseStorage.getInstance().getReference("all/$imageID2.jpg")

        upload = findViewById(R.id.uploadButton)
        button1 = findViewById(R.id.imageButton1)
        button2 = findViewById(R.id.imageButton2)
        button3 = findViewById(R.id.imageButton3)
        button4 = findViewById(R.id.imageButton4)
        buttons = listOf(button1, button2, button3, button4)

        // EDIT disable buttons until all images are ready
        buttons.forEach {
            it.setEnabled(false)
        }

        upload.setOnClickListener(View.OnClickListener {
            try {
                val localfile = File.createTempFile("tempfile", ".jpg")
                aDatabase.getFile(localfile).addOnSuccessListener {
                    val bitmap = BitmapFactory.decodeFile(localfile.absolutePath)
                    bitmapArray.add(bitmap)

                    // EDIT add the image twice here instead of duplicating later
                    bitmapArray.add(bitmap)

                    // EDIT count this image as ready
                    val totalImagesReady = numImagesReady.incrementAndGet()
                    
                    // EDIT once all images are ready, shuffle and enable the buttons
                    if (totalImagesReady == numImages) {
                        bitmapArray.shuffle()
                        buttons.forEach { it.setEnabled(true) }
                    }

                }.addOnFailureListener {
                    Log.w("myapplication", "ERROR RETRIEVING IMAGE")
                    Toast.makeText(this, "ERROR RETRIEVING IMAGE", Toast.LENGTH_SHORT).show()
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }

            try {
                // SUGGESTION especially if this will be implemented 8x8, you might want to try implementing this in a loop instead of duplicating code
                val localfile = File.createTempFile("tempfile1", ".jpg")
                sDatabase.getFile(localfile).addOnSuccessListener {
                    val bitmap = BitmapFactory.decodeFile(localfile.absolutePath)
                    bitmapArray.add(bitmap)

                    // EDIT add the image twice here instead of duplicating later
                    bitmapArray.add(bitmap)

                    // EDIT count this image as ready
                    val totalImagesReady = numImagesReady.incrementAndGet()
                    
                    // EDIT once all images are ready, shuffle and enable the buttons
                    if (totalImagesReady == numImages) {
                        bitmapArray.shuffle()
                        buttons.forEach { it.setEnabled(true) }
                    }

                }.addOnFailureListener {
                    Log.w("myapplication", "ERROR RETRIEVING IMAGE")
                    Toast.makeText(this, "ERROR RETRIEVING IMAGE", Toast.LENGTH_SHORT).show()
                }
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
// EDIT moved            ///    DUPLICATE
// EDIT refactor         bitmapArray.addAll(bitmapArray)
// EDIT moved            ///SHUFFLE
// EDIT moved            bitmapArray.shuffle()
// EDIT remove           Log.w("myapplication", bitmapArray.size.toString())
        })

        buttons.forEachIndexed { index, button ->
            button.setOnClickListener(View.OnClickListener {
                button.setImageBitmap(bitmapArray[index])
            })
        }
    }
}

相关问题