Первое значение BindingAdapter LiveData всегда пустое - PullRequest
5 голосов
/ 13 апреля 2019

Я пытаюсь обработать значение LiveData (profilePicture: Bitmap) в функции BindingAdapter, но первое значение всегда null .Адаптер для переплета - это ViewSwitcher с ProgressBar и ImageView.

Получение изображения профиля из 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() вызывается два раза.Но для меня важнее понять, почему первое значение равно 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

Ответы [ 3 ]

3 голосов
/ 13 апреля 2019

Когда вы определяете LiveData, его начальное значение будет нулевым, даже если его тип не обнуляется:

val downloadPictureResult = MutableLiveData<Bitmap>()
// Here, downloadPictureResult.value is null

В вашем случае значение LiveData, возвращаемое downloadProfilePic()будет нулевым, пока изображение не будет загружено, что будет происходить асинхронно внутри обратного вызовакогда downloadPictureResult возвращается downloadProfilePic() в первый раз.

1 голос
/ 18 мая 2019

Как сказали другие ответы, первое значение всегда будет нулевым.Тем не менее, вы можете получить значение, когда оно будет готово, с помощью наблюдателя, а затем отписаться от него, когда у вас есть изображение.

val pic = downloadProfilePic()
pic.observe(owner, object : Observer<BitMap?> {
    override fun onChanged(b: BitMap?){
        if(b != null){
            setProfilePicture(yourView, b)
            pic.removeObserver(this)
        }
    }
})
1 голос
/ 14 мая 2019

Давайте разберемся шаг за шагом о том, как LiveData работает в вашем случае (в целом) :

  1. Ваш метод 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 как Привязка данных получает начальное значение независимо от того, что есть в LiveData, а затем наблюдает за ним далее.

Итак, здесь вы инициализировали LiveData с нулевым значением из Bitmap во время этого кода val downloadPictureResult = MutableLiveData<Bitmap>() возвращает нулевое значение для самого первого раза.

И затем происходит обратный вызов из addOnCompleteListener метода и значенияв качестве параметра «liveata» присваивается значение downloadPictureResult.value = responseBitmap или null в случае ошибки.

Вот почему есть два вызова для LiveData в вашем BindingAdapter методе setProfilePicture().

Примечание: Простойхак, который вы можете сделать, если не хотите, чтобы два обратных вызова делали ваш обратный вызов синхронным, а не асинхронным.

...