android - 自定义 View 上的数据绑定(bind) "Can' t 引用 .setTag 空引用对象”

标签 android android-databinding

我遇到了一个问题,我已经为此付出了至少 2 周的时间,我感到非常震惊,以至于这么多年后我有点忘记了数据绑定(bind)是如何工作的以及如何为“CUSTOM VIEWS”正确设置它.我决定在一个非常简单的项目上检查它,以便将它与我当前的项目隔离开来。一个非常简单的 HelloWorld 应用程序,它基本上使用数据绑定(bind)将 Hello World 输出到屏幕。该项目包含以下文件:

主要 Activity .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>

现在这是问题最重要的部分。这是一个自定义 View CustomView。我想将一个特定的数据“String”绑定(bind)到这个 View 中,这样它就可以在这个 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 会膨胀一个可以绑定(bind)的 View :

<?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>

所以我基本上是绑定(bind)一个字符串到这个自定义 View (它由(据说)其布局中的许多 View 组成),一旦我从外部设置它,比如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)

我的应用突然崩溃了,我陷入了 panic 。我只是不再了解 DataBinding 的基础知识。当我只是对 View 进行数据绑定(bind)时效果很好,但我对自己的自定义 View 进行所有数据绑定(bind)都没有运气。让我发疯的一件事是这会在自动生成的代码上崩溃。我完全不知道它是如何生成引用它生成的 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 相关的问题,直到我在稳定的环境中构建这个项目并且无论如何它们的行为都是一样的。

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

最佳答案

This is my curse. Any help to lessen my suffering would be appreciated!

我会努力的。

删除您编写的两个 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
        }
}

将 CustomView 布局中的 app:message="@{message}" 部分替换为 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,因为数据绑定(bind)库会在编译期间自动检测从 Kotlin 类中的消息字段生成的 setMessage() 方法。这同样适用于 TextView,数据绑定(bind)库将检测到有一个 setText() 方法并将其用于 android:text="@{message}"

关于android - 自定义 View 上的数据绑定(bind) "Can' t 引用 .setTag 空引用对象”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53748196/

相关文章:

android,videoView打不开这个视频在线视频

android - 使用 Android 数据绑定(bind)动态切换布局元素的可见性。

android - 尝试将数据绑定(bind)提供的上下文变量与 BaseObservable 一起使用时出错

android - 是否可以将参数发送到来自 xml View 的绑定(bind)事件

android - recyclerView 中的数据绑定(bind)

android-databinding - Android Studio 3.5 DataBinding BR 字段显示为未定义

java - MediaRecorder 停止在无效状态下调用 : 1

Android 实时多人游戏通知连接丢失

android - 如何检查之前启动的自定义自己的服务是否正在运行

java - 如何显示 firebase 数据库中的所有标记?