55

我想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但我想知道如何正确地做到这一点。

4

7 回答 7

98

原因:

首先要知道的是 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>

或者

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

那么你应该能够android:background像你最初想要的那样使用,但提供可绘制而不是颜色:

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

这里的 arguments 具有兼容的类型: first isDrawable和 second is null 所以它也可以转换为 a Drawable

2.作为资源id

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

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

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

将 0 作为“null 资源 id”传递是安全setBackgroundResource的,因为检查方法View是否resid不同于 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;
}
于 2015-10-11T12:35:14.967 回答
22

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

像这样

android:background="@{article.sponsored ? @color/sponsored_article_background : @color/your_default_color}"
于 2015-10-10T08:54:30.080 回答
10

您可以使用的一种方法是编写一个自定义@BindingConversion来为您处理这个问题:

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

有了这个,您可以将任何接受 aColorDrawable的属性设置为整数颜色值(如 0 或@android:color/transparent),并自动为您转换为轻量级 @null。

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

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


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

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

...并像这样写下你的表达式:

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

...尽管我个人建议将这种条件逻辑放在您的数据绑定适配器方法中,例如使用getArticleBackground()返回 Drawable 或 null 的方法。一般来说,如果您避免将决策逻辑放在布局文件中,事情会更容易调试和跟踪。

于 2016-06-21T18:26:57.303 回答
1

试试这个:

@Bindable
private int color;

并在构造函数中

color = Color.parseColor("your color in String for examp.(#ffffff)")

在 xml 中:

android:textColor = "@{data.color}"
于 2017-08-30T19:30:03.680 回答
0

本文中,您可以找到两个很好的解决方案,但就我而言,只有一个可行,因为我想更改材质按钮中的背景色调,这是我的绑定适配器:

首先,创建一个 Kotlin 文件并粘贴此适配器方法:

package com.nyp.kartak.utilities

import android.content.res.ColorStateList
import androidx.databinding.BindingAdapter
import com.google.android.material.button.MaterialButton
import com.nyp.kartak.model.ReceiptUserPurchaseModel

@BindingAdapter("backgroundTintBinding")
fun backgroundTintBinding(button: MaterialButton, model: ReceiptUserPurchaseModel) {
    button.backgroundTintList = ColorStateList.valueOf(button.resources.getColor( model.color))
}

第二次在你的xml中使用它:

<data>
    <variable
        name="model"
        type="com.nyp.kartak.model.ReceiptUserPurchaseModel" />
</data>

// .....

    <com.google.android.material.button.MaterialButton
        android:id="@+id/payBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{model.getAction()}"
        app:backgroundTintBinding="@{model}" />
于 2019-06-12T07:56:23.130 回答
0

这确实是旧帖子,但我想提出另一种解决方案。

  1. 在 DRAWABLE 中声明自定义样式/背景**

我有四种相似的样式,所以我将只粘贴其中一种。

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/colorAccent">
    <item>
        <layer-list>
            <item>
                <shape android:shape="oval">
                    <stroke
                        android:width="1dp"
                        android:color="@color/colorAccent" />
                    <solid android:color="@color/colorPrimaryDark" />
                    <size
                        android:width="200dp"
                        android:height="200dp" />
                </shape>
            </item>
            <item
                android:width="100dp"
                android:height="100dp"
                android:gravity="center"
                android:drawable="@drawable/ic_car_white" />
        </layer-list>
    </item>
</ripple>

当我设置这种样式时,我的按钮如下所示:

在此处输入图像描述

  1. 在模型/处理程序类中准备可绑定值

就我而言,我在 ActivityMainEventHandler 类中有以下代码

@Bindable
public Drawable getConenctButtonStyle() {
    // here i'm checking connection state but you can do own conditions
    ConnectionState state = Communication.getInstance().getConnectionState();
    if (state != null) switch (state) {
        case CONNECTED:
            return ctx.getDrawable(R.drawable.circle_btn_state_green);
        case CONNECTING:
        case DISCONNECTING:
            return ctx.getDrawable(R.drawable.circle_btn_state_orange);
        case DISCONNECTED:
            return ctx.getDrawable(R.drawable.circle_btn_state_red);
    }
    return ctx.getDrawable(R.drawable.circle_btn_state_first);
}
  1. 将您的课程传递给您的视图

创建活动:

 bind = DataBindingUtil.setContentView(this, R.layout.activity_main);
        handler = new ActivityMainEventHandler(this, bind);
        bind.setMainHandler(handler);

我们活动的 XML

   <data>
            <variable
                name="mainHandler"
                type="xx.xxx.packagename.eventHandlers.ActivityMainEventHandler" />
        </data>
  1. 设置您的背景以查看如下

标记:

 android:background="@{mainHandler.conenctButtonStyle}"
  1. 然后,如果您想再次检查 step2 的条件并重绘视图,只需调用

代码:

//BR.conenctButtonStyle it's automatically generated id
bind.notifyPropertyChanged(BR.conenctButtonStyle);
于 2020-02-25T15:09:05.143 回答
0

另一个解决方案,如果你只想设置backgroundTint而不是整体background,你可以像这样使用它:

如果您的 min api 为 21,您将需要 import ContextCompat

<import type="androidx.core.content.ContextCompat" />

...

app:backgroundTintList="@{ContextCompat.getColorStateList(context, [funtion_to_get_your_color_res_id]))}"
于 2020-10-18T11:01:32.980 回答