6

我正在尝试处理函数中的LiveData值 ( profilePicture: Bitmap),BindingAdapter但第一个值始终为null。绑定适配器是一个ViewSwitcherwithProgressBarImageView

像这样从firebase获取个人资料图片:

    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;
    }

因为第一个值是null而第二个是预期的位图对象,所以view.showNext()被调用了两次。但对我来说更重要的是要理解为什么 firstvalue 为null,因为该setProfilePicture方法会有更多的逻辑。

BindingAdapter 看起来像这样。

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

日志:

2019-04-13 17:53:01.658 11158-11158/... D/PPSS: null
2019-04-13 17:53:02.891 11158-11158/... D/PPSS: android.graphics.Bitmap@8b6ecb8
4

3 回答 3

5

当您定义 aLiveData时,即使其类型不可为空,它的初始值也将为 null:

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时仍然为 null 。downloadPictureResultdownloadProfilePic()

于 2019-04-13T16:50:42.997 回答
2

正如其他答案告诉您的那样,第一个值将始终为空。但是,您可以在准备好使用观察者时获取该值,然后在您拥有图像时取消订阅它。

val pic = downloadProfilePic()
pic.observe(owner, object : Observer<BitMap?> {
    override fun onChanged(b: BitMap?){
        if(b != null){
            setProfilePicture(yourView, b)
            pic.removeObserver(this)
        }
    }
})
于 2019-05-18T16:40:31.813 回答
2

让我们逐步了解LiveData您的情况(通常)如何工作:

  1. 您的方法downloadProfilePic()返回nullable作为返回类型。方法包含异步代码,意思是即使在返回值之后它的执行也会发生。LiveDataBitmapaddOnCompleteListenerLiveData

这里:

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;
}
  1. 您正在返回downloadPictureResult作为全局初始化为val downloadPictureResult = MutableLiveData<Bitmap>()可变实时数据的方法的结果,以便我们之后可以对其进行修改。这发生在addOnCompleteListener.

  2. 现在大概,当您的视图(Activity/Fragment)被加载并因此您从ViewModel作为DataBinding添加实时数据时,它会获取初始值LiveData,然后进一步观察它。

  3. 因此,在这里,您已在此代码期间LiveData使用null 值进行了初始化,它第一次返回null 值Bitmapval downloadPictureResult = MutableLiveData<Bitmap>()

  4. 然后从方法发生回调,如果错误,最终addOnCompleteListener将 value 分配为 livedatadownloadPictureResult.value = responseBitmapnull 。

LiveData这就是为什么在你的BindingAdapter方法中有两个调用setProfilePicture()

注意:如果您不想要两个回调,您可以做的简单技巧是使您的回调同步而不是异步。

于 2019-05-14T05:40:38.697 回答