我正在尝试在LiveData
函数中处理profilePicture: Bitmap
值(BindingAdapter
),但是第一个值始终为 null 。绑定适配器是具有ViewSwitcher
和ProgressBar
的{{1}}。
像这样从Firebase获取个人头像:
ImageView
由于第一个值为 null ,第二个为预期的位图对象,因此 val downloadPictureResult = MutableLiveData<Bitmap>()
// ...
fun downloadProfilePic(): LiveData<Bitmap?> {
val imageRef = storage.getReference("images/$uid/profile/profile_picture.jpg")
imageRef.getBytes(ONE_MEGABYTE).addOnCompleteListener { task ->
if (task.isSuccessful) {
//...
downloadPictureResult.value = responseBitmap
//...
} else {
downloadPictureResult.value = null
Log.d(TAG, task.exception?.localizedMessage)
}
}
return downloadPictureResult;
}
被调用了两次。但是对我来说,更重要的是要理解为什么firstvalue是 null 的原因,因为view.showNext()
方法将具有更多的逻辑。
BindingAdapter看起来像这样。
setProfilePicture
日志:
fun setProfilePicture(view: ViewSwitcher, profilePicture: Bitmap?) {
Log.d("PPSS", profilePicture.toString())
val imageView: ImageView = view[1] as ImageView
imageView.setImageDrawable(view.context.getDrawable(R.drawable.account_circle_24dp))
profilePicture.let { picture ->
if (picture != null) {
val rounded = RoundedBitmapDrawableFactory.create(view.resources, picture)
rounded.isCircular = true
imageView.setImageDrawable(rounded)
view.showNext()
} else {
view.showNext()
}
}
答案 0 :(得分:3)
定义LiveData
时,即使其类型不可为空,其初始值也将为空:
val downloadPictureResult = MutableLiveData<Bitmap>()
// Here, downloadPictureResult.value is null
在您的情况下,LiveData
返回的downloadProfilePic()
的值为空,直到下载图片为止,该值将在回调addOnCompleteListener
中异步发生:
fun downloadProfilePic(): LiveData<Bitmap?> {
...
imageRef.getBytes(ONE_MEGABYTE).addOnCompleteListener { task ->
...
// This happens asynchronously, likely after downloadProfilePic()
// has already returned
downloadPictureResult.value = responseBitmap
...
}
return downloadPictureResult;
}
这就是为什么传递给适配器的第一个值为null的原因,因为downloadPictureResult.value
首次返回downloadPictureResult
时downloadProfilePic()
仍然为null。
答案 1 :(得分:1)
让我们逐步了解关于LiveData
在您的情况下的工作方式(通常):
downloadProfilePic()
返回可空LiveData
的Bitmap
作为返回类型。方法包含addOnCompleteListener
的异步代码,这意味着即使返回了LiveData
值,它的执行也会发生。这里:
fun downloadProfilePic(): LiveData<Bitmap?> {
val imageRef = storage.getReference("images/$uid/profile/profile_picture.jpg")
imageRef.getBytes(ONE_MEGABYTE).addOnCompleteListener { task ->
if (task.isSuccessful) {
//...
downloadPictureResult.value = responseBitmap
//...
} else {
downloadPictureResult.value = null
Log.d(TAG, task.exception?.localizedMessage)
}
}
return downloadPictureResult;
}
作为方法的结果,您将返回downloadPictureResult
,该方法已全局初始化为val downloadPictureResult = MutableLiveData<Bitmap>()
可变活数据,以便我们以后可以对其进行修改。发生在addOnCompleteListener
的回调中。
现在大概是,当视图(Activity/Fragment)
被加载,因此您已经将ViewModel
中的实时数据添加为 DataBinding 时,它将获得初始值在LiveData
中,然后进一步观察。
因此,在此,您已在代码LiveData
期间用Bitmap
的空值初始化了val downloadPictureResult = MutableLiveData<Bitmap>()
,它返回了空值< / strong>,这是第一次。
然后从addOnCompleteListener
方法进行回调,并在发生错误时最终为livedata分配值downloadPictureResult.value = responseBitmap
或 null 。
这就是为什么在您的
LiveData
方法BindingAdapter
中有两个对setProfilePicture()
的调用。
注意:如果您不希望两个回调使您的回调是同步的而不是异步的,则可以执行简单的操作。
答案 2 :(得分:1)
正如其他答案告诉您的那样,第一个值将始终为null。但是,当您准备好使用观察器获取值时,然后在拥有图像后就可以取消订阅。
val pic = downloadProfilePic()
pic.observe(owner, object : Observer<BitMap?> {
override fun onChanged(b: BitMap?){
if(b != null){
setProfilePicture(yourView, b)
pic.removeObserver(this)
}
}
})