自定义视图上的数据绑定“无法在空引用对象上引用.setTag”

时间:2018-12-12 17:18:01

标签: android android-databinding

我遇到了至少已经工作了至少2周的问题,我感到非常傻眼,以至于这么多年后,我有点忘记了数据绑定的工作原理以及如何正确设置“自定义视图” 。我决定在一个非常简单的项目中进行检查,以使其与当前项目隔离。一个非常简单的HelloWorld应用程序,它基本上是使用数据绑定将Hello World输出到屏幕上的。该项目包含以下文件:

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(LayoutInflater.from(this))
        setContentView(binding.root)

        binding.message = "Hello World!"
    }
}

activity_main.xml

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

    <data>
        <variable name="message" type="String" />
    </data>

    <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity">

        <com.neonapps.android.sample.databinding.CustomView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"


            <!-- Please take note I am data binding on my custom view -->
            app:message="@{message}"



            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>

    </android.support.constraint.ConstraintLayout>

</layout>

现在这是问题的最重要部分。这是一个自定义视图CustomView。我想将特定的数据'String'绑定到该视图中,这样它就可以在此CustomView上输出“ Hello World”:

class CustomView(context : Context, attrs : AttributeSet, defStyleAttrs : Int, defStylRes : Int) : RelativeLayout(context){

    constructor(context : Context, attrs : AttributeSet) : this(context, attrs, 0, 0)

    constructor(context : Context, attrs : AttributeSet, defStyleAttrs : Int) : this(context, attrs, defStyleAttrs, 0)

    private var myMessage : String? = null
        set(value){
            value.let{
                field = it
                binding.message = field
            }
        }

    private val binding : LayoutCustomViewBinding = LayoutCustomViewBinding.inflate(LayoutInflater.from(context), this, true)

    init {
        binding.message?.let{
            binding.message = it
        }
    }

    fun setMessage(message : String?){
        myMessage = message
    }
}

@BindingAdapter(value = ["message"])
fun setMessage(view : TextView, message : String?)
{
    message?.let{
        view.text = it
    }
}

@BindingAdapter(value = ["message"])
fun setMessage(view : CustomView, message : String?)
{
    message?.let{
        view.message = it
    }
}

这是要抓住的地方。 CustomView使视图可以绑定

<?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="message" type="String" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:message="@{message}"
            tools:text="Hello World"/>

    </RelativeLayout>

</layout>

因此,一旦我从外部进行设置,就像上面的activity_main.xml一样,我基本上就在该自定义视图(假定(由布局中的许多视图组成)上)将字符串绑定

activity_main.kt

<layout
    ...>

    <data>
        ...
    </data>

    <android.support.constraint.ConstraintLayout
            ...>

        <com.neonapps.android.sample.databinding.CustomView
            ...


            <!-- Please take note I am data binding on my custom view -->
            app:message="@{message}"



            .../>

    </android.support.constraint.ConstraintLayout>

</layout>

一旦我构建了整个项目,一切似乎都可以正常工作。我现在运行该应用程序,出现以下错误:

Attempt to invoke virtual method 'void ******.databinding.CustomView.setTag(java.lang.Object)' on a null object reference
        at com.neonapps.android.sample.databinding.databinding.ActivityMainBindingImpl.<init>(ActivityMainBindingImpl.java:37)
        at com.neonapps.android.sample.databinding.databinding.ActivityMainBindingImpl.<init>(ActivityMainBindingImpl.java:29)
        at com.neonapps.android.sample.databinding.DataBinderMapperImpl.getDataBinder(DataBinderMapperImpl.java:44)
        at android.databinding.MergedDataBinderMapper.getDataBinder(MergedDataBinderMapper.java:74)
        at android.databinding.DataBindingUtil.bind(DataBindingUtil.java:199)
        at android.databinding.DataBindingUtil.inflate(DataBindingUtil.java:130)
        at com.neonapps.android.sample.databinding.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:49)
        at com.neonapps.android.sample.databinding.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:43)
        at *****.MainActivity.onCreate(MainActivity.kt:12)
        at android.app.Activity.performCreate(Activity.java:6904)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1136)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3266)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3415) 
        at android.app.ActivityThread.access$1100(ActivityThread.java:229) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:148) 
        at android.app.ActivityThread.main(ActivityThread.java:7406) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

我的应用突然崩溃了,我陷入了恐慌。我只是不了解DataBinding的基础。当我仅在视图上进行数据绑定时,它的效果很好,但我对自己的自定义视图上的所有数据绑定都没有运气。令我发疯的一件事是,它在自动生成的代码上崩溃了。我完全不知道它是如何生成一个代码的,该代码引用它所生成的null而不给它分配引用。我投降了,有件事我很想念。

我肯定错过了一些东西,我似乎无法发现它。我一直在交叉引用DataBinding库文档,但对我而言没有任何用处。

我尝试过此代码

Android Studio: 3.4 Canary 7
Kotlin: 1.3.11

Android Studio: 3.2.1
Kotlin: 1.2.71

首先,我认为这可能是与Kotlin / Build config / gradle相关的问题,直到我在稳定的环境上构建此项目并且它们的行为相同为止。

这是我的诅咒。任何减轻我痛苦的帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

  

这是我的诅咒。任何减轻我痛苦的帮助将不胜感激!

我会尝试的。

删除您编写的两个BindingAdapter并将类重写为:

class CustomView : RelativeLayout {

    constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0, 0)
    constructor(context: Context, attrs: AttributeSet, defStyleAttrs: Int) :
            this(context, attrs, defStyleAttrs, 0)
    constructor(context: Context, attrs: AttributeSet, defStyleAttrs: Int, defStylRes: Int) :
            super(context, attrs, defStyleAttrs, defStylRes)

    private val binding: LayoutCustomViewBinding = LayoutCustomViewBinding.inflate(LayoutInflater.from(context), this, true)

    var message: String? = null
        set(value) {
            binding.message = value
        }
}

app:message="@{message}"替换CustomView布局中的android:text="@{message}"部分:

<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="message" type="String" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{message}"
            tools:text="Hello World"/>

    </RelativeLayout>

</layout>

说明:

您不需要编写的BindingAdapters,因为数据绑定库会自动检测在编译过程中从Kotlin类的message字段生成的setMessage()方法。对于TextView同样适用,数据绑定库将检测到存在setText()方法并将其用于android:text="@{message}"