Используйте библиотеку DataBinding для установки ресурса цвет фона или нулевого

Я хотел бы установить цвет фона или null в моем представлении, используя библиотеку DataBinding, но я получаю исключение, пытаясь запустить его.

 java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference 

Вот как я это делаю:

 android:background="@{article.sponsored ? @color/sponsored_article_background : null}" 

Я также попытался установить преобразование, но это не сработало.

 @BindingConversion public static ColorDrawable convertColorToDrawable(int color) { return new ColorDrawable(color); } 

В конце концов, я решил его обходным путем с помощью @BindingAdapter но я хотел бы знать, как это сделать правильно.

Solutions Collecting From Web of "Используйте библиотеку DataBinding для установки ресурса цвет фона или нулевого"

Причина:

Первое, что нужно знать, это то, что библиотека DataBinding уже предоставляет convertColorToDrawable конверсии convertColorToDrawable расположенный в android.databinding.adapters.Converters.convertColorToDrawable(int) .

Использование android:background должен «теоретически» работать, потому что он имеет соответствующий setBackground(Drawable) . Проблема в том, что он видит, что вы пытаетесь передать цвет в качестве первого аргумента, поэтому он попытался запустить этот конвертер, прежде чем применять его к setBackground(Drawable) . Если привязка данных решает использовать конвертер, он будет использовать его для обоих аргументов, так же как и для null , перед тем как применить конечный результат к сеттеру.
Поскольку null не может быть castes для int (и вы не можете вызвать intValue() на нем), он выдает NullPointerException .

Существует упоминание о том, что смешанные типы аргументов не поддерживаются в официальном руководстве по привязке данных .

Вот два решения этой проблемы. Хотя вы можете использовать любое из этих двух решений, первое намного проще.

Решения:

1. Как доступный

Если вы определяете свой цвет не как цвет, а как вытягиваемый в своих ресурсах (он может быть в нашем файле colors.xml:

 <drawable name="sponsored_article_background">#your_color</drawable> 

или

 <drawable name="sponsored_article_background">@color/sponsored_article_background</drawable> 

То вы должны иметь возможность использовать android:background как вы изначально хотели, но предоставляющий возможность рисования вместо цвета:

 android:background="@{article.sponsored ? @drawable/sponsored_article_background : null}" 

Здесь аргументы имеют совместимые типы: сначала – Drawable а second – null, поэтому его также можно отнести к Drawable .

2. В качестве идентификатора ресурса

 app:backgroundResource="@{article.sponsored ? R.color.sponsored_article_background : 0}" 

Но также потребуется добавить свой импорт R-класса в раздел data :

 <data> <import type="com.example.package.R" /> <variable ... /> </data> 

Передача 0 в качестве «идентификатора нулевого ресурса» безопасна, потому setBackgroundResource метод setBackgroundResource View проверяет, отличается ли значение, отличное от 0, и устанавливает значение null в качестве фона в противном случае. Там нет ненужных прозрачных объектов.

 public void setBackgroundResource(int resid) { if (resid != 0 && resid == mBackgroundResource) { return; } Drawable d= null; if (resid != 0) { d = mResources.getDrawable(resid); } setBackgroundDrawable(d); mBackgroundResource = resid; } 

Я думаю, вы должны попробовать color умолчанию вместо null

как это

 android:background="@{article.sponsored ? @color/sponsored_article_background : @color/your_default_color}" 

Один из подходов, который вы можете использовать, – написать пользовательскую @BindingConversion чтобы позаботиться об этом для вас:

 @BindingConversion public static ColorDrawable convertColorToDrawable(int color) { return color != 0 ? new ColorDrawable(color) : null; } 

С помощью этого вы можете установить любой атрибут, который принимает ColorDrawable для целочисленного значения цвета (например, 0 или @android:color/transparent ) и автоматически преобразует его в легкий вес @null для вас.

(В то время как встроенный convertColorToDrawable(int) всегда создает объект ColorDrawable , даже если цвет прозрачен.)

Примечание: для того, чтобы этот метод использовался вместо встроенной @BindingConversion , он должен возвращать ColorDrawable а не Drawable иначе встроенный метод будет рассматриваться как более конкретный / соответствующий.


Другим подходом является использование статического метода для преобразования из цвета в Drawable в ваше выражение привязки данных, чтобы совместить типы значений. Например, вы можете импортировать встроенный класс Converters :

 <data> <import type="android.databinding.adapters.Converters"/> </data> 

… и напишите свое выражение следующим образом:

 android:background="@{article.sponsored ? Converters.convertColorToDrawable(@color/sponsored_article_background) : null}" 

… хотя я лично рекомендовал бы вместо этого использовать getArticleBackground() условную логику в методе адаптера привязки данных, например, используя метод getArticleBackground() который возвращает Drawable или null. В общем, легче отлаживать и отслеживать, если вы не ставите логику принятия решений в свои файлы макета.