我遇到了至少已经工作了至少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相关的问题,直到我在稳定的环境上构建此项目并且它们的行为相同为止。
这是我的诅咒。任何减轻我痛苦的帮助将不胜感激!
答案 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}"
。