onClick 方法不是从带有 dataBinding 的 .xml 绑定表达式中调用的
Posted
技术标签:
【中文标题】onClick 方法不是从带有 dataBinding 的 .xml 绑定表达式中调用的【英文标题】:onClick method is not called from .xml binding expression with dataBinding 【发布时间】:2022-01-10 11:25:33 【问题描述】:我正在尝试通过在按钮的 onClick 中使用绑定表达式(这些实际上是什么,属性?)从“content_main.xml”调用“MainActivity.kt”中的函数。
问题是,当我按下八个按钮时,它们永远不会被调用。
这就是“content_main.xml”文件中代码段落的样子(为了更好的可读性,我省略了不必要的代码):
<?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">
<data>
<variable
name="viewModel"
type="com.ronnabyte.ntatools.model.FuelViewModel" />
<variable
name="activity"
type="com.ronnabyte.ntatools.MainActivity" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_
android:layout_
app:layout_behavior="@string/appbar_scrolling_view_behavior">
...
<Button
android:id="@+id/clear_required_fuel_btn"
style="@style/Widget.MaterialComponents.Button.OutlinedButton.Icon"
android:layout_
android:layout_
android:onClick="@()->activity.clearRequiredFuel()"
android:text="@string/clear_fuel_on_board"
app:icon="@drawable/ic_baseline_delete_24"
app:layout_constraintBottom_toBottomOf="@+id/required_fuel_ed"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/required_fuel_ed"
app:layout_constraintTop_toTopOf="@+id/required_fuel_ed" />
...
<Button
android:id="@+id/clear_remaining_fuel_btn"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_
android:layout_
android:onClick="@()->activity.clearRemainingFuel()"
android:text="@string/clear_fuel_on_board"
app:icon="@drawable/ic_baseline_delete_24"
app:layout_constraintBottom_toBottomOf="@+id/remaining_fuel_ed"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/remaining_fuel_ed"
app:layout_constraintTop_toTopOf="@+id/remaining_fuel_ed" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
以及“MainActivity.kt”中的代码:
package com.ronnabyte.ntatools
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.LifecycleOwner
import com.ronnabyte.ntatools.databinding.ActivityMainBinding
import com.ronnabyte.ntatools.model.FuelViewModel
class MainActivity : AppCompatActivity()
private lateinit var binding: ActivityMainBinding
private val viewModel: FuelViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
setSupportActionBar(binding.toolbar)
binding.fab.setOnClickListener
viewModel.calculateFuelUplift()
override fun onCreateOptionsMenu(menu: Menu): Boolean
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
override fun onOptionsItemSelected(item: MenuItem): Boolean
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
return when (item.itemId)
R.id.action_settings -> true
else -> super.onOptionsItemSelected(item)
fun clearRequiredFuel()
Log.d("MainActivity", "ClearRequiredFuel has been called.")
binding.contentMain.apply
requiredFuelUpliftTv.text = ""
requiredFuelEd.text.clear()
requiredFuelEd.requestFocus()
fun clearRemainingFuel()
Log.d("MainActivity", "ClearRemainingFuel has been called.")
binding.contentMain.apply
requiredFuelUpliftTv.text = ""
remainingFuelEd.text.clear()
requiredFuelEd.requestFocus()
感谢任何帮助,非常感谢。
编辑:这里是 gradle 文件:
plugins
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
android
compileSdk 31
defaultConfig
applicationId "com.ronnabyte.ntatools"
minSdk 26
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildTypes
release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android- optimize.txt'), 'proguard-rules.pro'
buildFeatures
dataBinding true
compileOptions
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
kotlinOptions
jvmTarget = '1.8'
dependencies
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.fragment:fragment-ktx:1.4.0'
【问题讨论】:
如果将这些方法移至ViewModel
并在MainActivity
订阅ViewModel
LiveData 会怎样?
即使我知道该怎么做,这不违反 viewModel 架构,它说 viewModel 不应该知道视图吗?我正在这两个函数中设置视图...抱歉,我对此很陌生。
我认为,我的假设是错误的。但是对于ViewModel
,这不会错。您将在ViewModel
中拥有LiveData
或MutableStateFlow
并在那里设置它的值。然后在MainActivity
中,您将从ViewModel
订阅此值。当ViewModel
中的数据发生变化时(LiveData 或 MutableStateFlow 会改变它的值),订阅者也会反映变化(requiredFuelUpliftTv.text = ""
等)。
【参考方案1】:
我发现了binding.activity = this
不起作用的问题。 binding
的类型为 ActivityMainBinding
,但变量 activity
是在 content_main.xml
中定义的,而不是 activity_main.xml
。
这就是为什么在装订上找不到它,所以一直变红。
【讨论】:
【参考方案2】:对您的代码进行以下小改动:
private lateinit var binding: ActivityMainBinding
private val viewModel: FuelViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?)
binding
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater) //<--
setContentView(binding.root) //<--
setSupportActionBar(binding.toolbar)
【讨论】:
这不起作用,代码运行低谷,但是当我按下按钮时仍然没有调用该函数。【参考方案3】:在您的onCreate
方法中添加这一行:
binding.activity = this
下面的演示代码:
class MainActivity : AppCompatActivity()
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
// without this line, test() will not called
binding.activity = this
fun test()
Log.d("test", "test")
<?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="activity"
type="com.example.myapplication.MainActivity" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_
android:layout_
tools:context=".MainActivity">
<Button
android:layout_
android:layout_
android:onClick="@() -> activity.test()"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
【讨论】:
不幸的是,这不起作用,我在活动中得到“未解决的参考”。 哪个变量未解析?我写了一个演示来测试,它工作。请检查我编辑的答案。 非常感谢您的调查,非常感谢。当我开始一个新项目并使用您提供的代码时,它就像您所说的那样完美运行。但是当我在我的项目中尝试“binding.activity = this”行时,“.activity”会变成红色,工具提示“未解析的引用:活动”。但是“绑定”与正在运行的示例的类型完全相同,即“私有最终后期初始化变量绑定:ActivityMainBinding”类型。我清理并重建了这个项目,但没有运气。我将尝试包含 gradle 文件,以便您有时间可以查看一下。非常感谢。以上是关于onClick 方法不是从带有 dataBinding 的 .xml 绑定表达式中调用的的主要内容,如果未能解决你的问题,请参考以下文章
java.lang.IllegalStateException:找不到带有 id_button 的方法 onClick 处理程序
Android 将 Activity 添加到带有 Intent 的对话框
调用函数onclick on some buttons而不影响单个onclick函数的按钮(已经为按钮分配) - JavaScript