【问题标题】:My application freezes when sending image to Firebase将图像发送到 Firebase 时我的应用程序冻结
【发布时间】:2020-08-20 04:37:21
【问题描述】:

我正在开发一个应用程序,我可以在其中为 recyclerview(recyclerview 后面的 imageview)选择背景。从图库中选择图像后,我想将其发送到 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 中执行上传代码,但问题仍然存在。如何解决这个错误?

提前致谢

【问题讨论】:

标签: android firebase kotlin firebase-storage


【解决方案1】:

像这样在新线程中设置图像:

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();

【讨论】:

  • 可能不应该在 kotlin 中做这种混乱的回调逻辑。在 kotlin 中,协程更合适。并且在生产中非常不鼓励使用 Thread.sleep,它只会阻塞线程(非常耗费资源)。再次发送可运行在 UI 线程上运行,因此此解决方案可能有 0 效果,甚至可能产生负面影响,因为您无缘无故地创建新线程。
  • 实际上在你的代码中 ui 线程或主线程正在重载,所以我只是建议你新线程
  • 其实不是我问这个问题的,顺便说一下android中的ui和主线程是一样的,见:stackoverflow.com/questions/3261370/…
【解决方案2】:

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

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

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

// Dispatchers.Default is used for resource intensive tasks and is backed by a CommonPool of threads, that can be reused with another coroutine
// NonCancellable overrides the job on ViewModelScope to become non-cancellable
viewModelOwner.viewModelScope.launch(Dispatchers.Default + NonCancellable) {
    // Your intensive task right here
    // if you want to do some operation like updating ui just use runOnUiThread{/* code */}
}

【讨论】:

    猜你喜欢
    • 2014-07-22
    • 2020-12-21
    • 1970-01-01
    • 2014-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多