使用DataBinding库设置背景颜色资源或null

Dam*_*tla 33 android android-layout android-databinding

我想设置背景颜色或null使用DataBinding库在我的视图上,但我尝试运行它时遇到异常.

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

我是这样做的:

android:background="@{article.sponsored ? @color/sponsored_article_background : null}"
Run Code Online (Sandbox Code Playgroud)

我也试过设置转换但它没有用.

@BindingConversion
public static ColorDrawable convertColorToDrawable(int color) {
   return new ColorDrawable(color);
}
Run Code Online (Sandbox Code Playgroud)

最后,我使用解决方法解决了它,@BindingAdapter但我想知道如何正确地做到这一点.

Mac*_*ęga 64

原因:

首先要知道的是DataBinding库已经提供了一个convertColorToDrawable绑定转换器android.databinding.adapters.Converters.convertColorToDrawable(int).

使用android:background应该"理论上"工作,因为它有相应的setBackground(Drawable)方法.问题是,它看到您尝试将颜色作为第一个参数传递,因此它尝试在将此转换器应用于setBackground(Drawable)方法之前启动它.如果数据绑定决定使用转换器,它将在两个参数上使用它,所以null在将最终结果应用于setter之前也是如此.
因为null不能成为int(并且你不能intValue()在它上面调用)它会抛出NullPointerException.

有人提到官方数据绑定指南中不支持混合参数类型.

以下是此问题的两种解决方案.虽然您可以使用这两种解决方案中的任何一种,但第一种解决方案更容易.

解决方案:

1.可以画画

如果您不是将颜色定义为颜色,而是将其定义为资源中的可绘制颜色(可以在我们的colors.xml文件中:

<drawable name="sponsored_article_background">#your_color</drawable>
Run Code Online (Sandbox Code Playgroud)

要么

<drawable name="sponsored_article_background">@color/sponsored_article_background</drawable>
Run Code Online (Sandbox Code Playgroud)

然后你应该能够android:background像你原来想要的那样使用但是提供可绘制而不是颜色:

android:background="@{article.sponsored ? @drawable/sponsored_article_background : null}"
Run Code Online (Sandbox Code Playgroud)

这里的参数有兼容的类型:first is Drawable和second是null所以它也可以强制转换为a Drawable.

2.作为资源ID

app:backgroundResource="@{article.sponsored ? R.color.sponsored_article_background : 0}"
Run Code Online (Sandbox Code Playgroud)

但它还需要在data部分中添加您的R类导入:

<data>
    <import type="com.example.package.R" />
    <variable ... />
</data>
Run Code Online (Sandbox Code Playgroud)

将0作为"空资源id"传递是安全的,因为检查setBackgroundResource方法View是否resid不同于0并且将null设置为背景drawable否则.这里没有创建不必要的透明可绘制对象.

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 我的模型上有这个方法 `public int getBackground(){ return read ? R.color.read_sms : R.color.unread_sms;}` 并使用 `app:backgroundResource = "@{sms.getBackground}"` 并且工作完美。 (2认同)

pRa*_*NaY 11

我认为你必须尝试默认color而不是null

像这样

android:background="@{article.sponsored ? @color/sponsored_article_background : @color/your_default_color}"
Run Code Online (Sandbox Code Playgroud)


Lor*_*rte 8

您可以使用的一种方法是编写自定义@BindingConversion以便为您处理:

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

使用此功能,您可以将任何接受a的属性设置ColorDrawable为整数颜色值(如0或@android:color/transparent),并将其自动转换为轻量级@null.

(即使内置convertColorToDrawable(int)转换器总是创建一个ColorDrawable对象,即使颜色是透明的.)

注意:为了使用此方法代替内置函数@BindingConversion,它必须返回a ColorDrawable而不是a Drawable- 否则内置方法将被视为更具体/适当.


另一种方法是使用静态方法将颜色转换为Drawable数据绑定表达式中的颜色,以使值类型匹配.例如,您可以导入内置Converters类:

<data>
    <import type="android.databinding.adapters.Converters"/>
</data>
Run Code Online (Sandbox Code Playgroud)

...并写下你的表达式:

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

...虽然我个人建议在数据绑定适配器方法中使用这种条件逻辑,例如使用getArticleBackground()返回Drawable或null的方法.通常情况下,如果您避免在布局文件中放置决策逻辑,则更容易调试和跟踪.