Исключение IllegalArgumentException при использовании привязки данных к ImageView с использованием LiveData

#android #kotlin #android-databinding #android-architecture-components #android-livedata

#Android #kotlin #android-привязка данных #android-архитектура-компоненты #android-livedata

Вопрос:

Я пытаюсь использовать привязку данных для добавления изображения в ImageView.

Я извлекаю объект из базы данных Room и предоставляю URL-адрес заголовка и изображения как LiveData. Я могу установить заголовок, но настройка изображения не выполняется.

Вот журнал ошибок

  Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter imageUrl
    at com.sample.databinding.detail.ArticleDetailsViewModel$Companion.loadImage(Unknown Source:7)
    at com.sample.databinding.detail.ArticleDetailsViewModel.loadImage(Unknown Source:2)
    at com.sample.databinding.detail.databinding.ActivityArticleDetailsBindingImpl.executeBindings(ActivityArticleDetailsBindingImpl.java:198)
    at androidx.databinding.ViewDataBinding.executeBindingsInternal(ViewDataBinding.java:448)
    at androidx.databinding.ViewDataBinding.executePendingBindings(ViewDataBinding.java:420)
    at androidx.databinding.ViewDataBinding$OnStartListener.onStart(ViewDataBinding.java:1633)
    at java.lang.reflect.Method.invoke(Native Method)
    at androidx.lifecycle.ClassesInfoCache$MethodReference.invokeCallback(ClassesInfoCache.java:215)
  

Вот строка в сгенерированном файле, которая не выполняется

 if ((dirtyFlags amp; 0x19L) != 0) {
        // api target 1

        com.sample.databinding.detail.ArticleDetailsViewModel.loadImage(this.backdrop, articleDetailsViewModelImageUrlGetValue);
    }
  

Вот мой код

activity_details.xml

 <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="articleDetailsViewModel"
            type="com.monzo.androidtest.detail.ArticleDetailsViewModel" />
    </data>

<androidx.coordinatorlayout.widget.CoordinatorLayout
    android:id="@ id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@ id/appbar"
        android:layout_width="match_parent"
        android:layout_height="256dp"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:contentScrim="?attr/colorPrimary"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@ id/collapsingToolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@ id/backdrop"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax"
                app:imageSource="@{articleDetailsViewModel.imageUrl}"/>

            <androidx.appcompat.widget.Toolbar
                android:id="@ id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:title="@{articleDetailsViewModel.articleTitle}"/>


        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>  

ActivityDetailsViewModel.kt

 package com.sample.databinding.detail

import android.app.Application
import android.widget.ImageView
import androidx.core.text.HtmlCompat
import androidx.databinding.BindingAdapter
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
import com.bumptech.glide.Glide
import com.sample.databinding.articles.model.Article
import com.sample.databinding.data.ArticlesDao
import kotlinx.coroutines.*


class ArticleDetailsViewModel(
        val database: ArticlesDao,
        val application: Application,
        val articleID: String) : ViewModel() {

    val article = database.getSpecificPost(articleID)

    val imageUrl = Transformations.map(article) {article.value?.thumbnail}
    val  articleTitle = Transformations.map(article) {article.value?.title}




    companion object {
        @JvmStatic
        @BindingAdapter("bind:imageSource")
        fun loadImage(view: ImageView, imageUrl: String) {
            if (!imageUrl.isEmpty()) {
                Glide.with(view.getContext())
                        .load(imageUrl)
                        .into(view)

            }

        }
    }
}  

Комментарии:

1. Что делают ваши кнопки запуска фрагмента кода ?

Ответ №1:

Видите, вы написали хороший код, но есть проблема в адаптере привязки

    @JvmStatic
        @BindingAdapter("bind:imageSource")
        fun loadImage(view: ImageView, imageUrl: String) {
            if (!imageUrl.isEmpty()) {
                Glide.with(view.getContext())
                        .load(imageUrl)
                        .into(view)
            }
        }
  

В этом коде вы ожидаете not null ImageUrl, но во время выполнения это значение равно null. Итак, это создает исключение.

Чтобы решить эту проблему, вы должны указать параметр ImageUrl nullable . И затем вы должны проверить, является ли ImageUrl нулевым или пустым. Итак, ваш метод привязки адаптера будет таким :

  @JvmStatic
        @BindingAdapter("bind:imageSource")
        fun loadImage(view: ImageView, imageUrl: String?) {
            if (!imageUrl.isNullOrBlank()) {
                Glide.with(view.getContext())
                        .load(imageUrl)
                        .into(view)
            }
        }
  

Надеюсь, это поможет. Счастливого кодирования 🙂

Комментарии:

1. Как мы узнаем, что вызывает imageUrl значение null?

Ответ №2:

Это должно быть

 imageUrl?.let {
     Glide.with(view.getContext())
          .load(imageUrl)
          .into(view)
}
  

Комментарии:

1. в вашем коде сбой был исправлен, но изображение не отображается

2. Потому imageUrl что равно нулю. Что вы ожидаете от «отображения» для null?

3. Я не ожидаю, что что-либо будет отображаться для null …. но если вы посмотрите «ВНИМАТЕЛЬНО» … ImageUrl — это LiveData…. Итак, я ожидал, что код Glide будет выполняться снова один раз, он имеет значение…. точно так же, как это делается для articleTitle

4. Каково ваше решение, @PrateekPhoenix?