Android 向Firebase发送图像时,我的应用程序冻结

Android 向Firebase发送图像时,我的应用程序冻结,android,firebase,kotlin,firebase-storage,Android,Firebase,Kotlin,Firebase Storage,我正在开发一个应用程序,在其中我可以为recyclerview(recyclerview后面的图像视图)选择背景。从图库中选择图像后,我想将其发送到firebase。然而,当上传图像时,我的应用程序被冻结,我无法滚动recyclerview 我的代码: override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(reques

我正在开发一个应用程序,在其中我可以为recyclerview(recyclerview后面的图像视图)选择背景。从图库中选择图像后,我想将其发送到firebase。然而,当上传图像时,我的应用程序被冻结,我无法滚动recyclerview

我的代码:

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == Activity.RESULT_OK) {
        /* code */
             else if (requestCode == BG_GALLERY_REQUEST_CODE) {
                val selectedPicture = data?.data
                val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
                val cursor = applicationContext.contentResolver.query(selectedPicture!!, filePathColumn, null, null, null)
                cursor!!.moveToFirst()

                val columnIndex = cursor.getColumnIndex(filePathColumn[0])
                val picturePath = cursor.getString(columnIndex)
                val bitmap = BitmapFactory.decodeFile(picturePath)
                cursor.close()
                backgroundUtils.salvarBackground(bitmap)

                val byteArrayOutputStream = ByteArrayOutputStream()
                bitmap?.compress(Bitmap.CompressFormat.JPEG, 80, byteArrayOutputStream)
                val dadosImagem = byteArrayOutputStream.toByteArray()

                val storageReference = ConfiguracaoFirebase.getFirebaseStorage()
                val imagemRef = storageReference
                        .child("imagens")
                        .child("backgrounds")
                        .child(UsuarioFirebase.getId() +
                                FileUtils.IMAGE_EXTENSION)
                val uploadTask = imagemRef.putBytes(dadosImagem)
                uploadTask.addOnSuccessListener {
                    imagemRef.downloadUrl.addOnSuccessListener { uri ->
                        ConfiguracaoFirebase.backgroundRef()
                                .child(UsuarioFirebase.getId())
                                .setValue(uri)
                        Log.e("upload", uri.toString())
                    }
                }.addOnFailureListener { exception ->
                    Log.e("upload", exception.message)
                }
            }
        } else if (resultCode == Activity.RESULT_CANCELED) {
            Log.i("REQUEST", "canceled")
        } else {
            toast(getString(R.string.oops_ocorreu_algum_erro))
        }
    }
我还尝试在AsyncTask中执行上载代码,但问题仍然存在。如何解决这个错误


提前感谢

在新线程中设置图像,如下所示:

Thread timer = new Thread()
            {
                public void run()
                {
                    try
                    {
                        sleep(2000);
                       runOnUiThread(new Runnable() {
                        public void run() {
                             splash.setImageResource(R.drawable.billboard_image);
                        }
                    });

                        sleep(2000);
                        runOnUiThread(new Runnable() {
                            public void run() {
                                 splash.setImageResource(R.drawable.square);
                            }
                        });
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                    finally
                    {
                       System.out.println("finally");
                    }
                }
            };
            timer.start();

可能是因为所有的生命周期方法都运行在android的主线程上。您正在回调(函数onActivityResult)本身中使用长时间运行和资源密集型任务,如
BitmapFactory.decodeFile()
Bitmap.compress()
,等等

您应该使用其他线程来执行此操作,但等待线程本身就是一种密集型资源,因此每次您想要发送图像时都创建一个新线程是不可取的

您可以在这里使用协同程序,使用ViewModel

//Dispatchers.Default用于资源密集型任务,由一个公共线程池支持,可与另一个协同程序重用
//NonCancellable将覆盖ViewModelScope上的作业,使其不可取消
viewModelOwner.viewModelScope.launch(Dispatchers.Default+不可取消){
//你的任务就在这里
//如果您想执行一些操作,比如更新ui,只需使用runOnUiThread{/*code*/}
}

可能是
putBytes
是一个阻塞函数,不是吗?我认为,这是线程的原因。从这里了解更多关于线程的信息可能不应该在kotlin中使用这种混乱的回调逻辑。在科特林,合作更合适。在生产环境中使用Thread.sleep是非常不受鼓励的,它只是阻塞了线程(非常占用资源)。你再次发送runnable以在UI线程上运行,因此此解决方案可能没有任何效果,甚至可能有负面影响,因为你无缘无故地创建了新线程。实际上,在你的代码中,UI线程或主线程超载,所以我建议你创建新线程实际上不是我提出的问题,顺便说一句,android中的ui和主线程是相同的,请参见: