Android 向Firebase发送图像时,我的应用程序冻结
我正在开发一个应用程序,在其中我可以为recyclerview(recyclerview后面的图像视图)选择背景。从图库中选择图像后,我想将其发送到firebase。然而,当上传图像时,我的应用程序被冻结,我无法滚动recyclerview 我的代码: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
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和主线程是相同的,请参见: