Android:如何将EditText的text属性传入其他View的DataBinding表达式
DataBinding传递EditText文本到ViewModel时编译失败问题解决
问题详情
布局内包含ID为quantityNumber的EditText(数量输入框)和ID为addToCartButton的Button,期望通过DataBinding在Button点击时将EditText的数值传递给ViewModel的onAddButtonClicked方法。尝试了两种写法:
android:onClick="@{() -> productDetailViewModel.onAddButtonClicked(quantityNumber.getText())}"
或
android:onClick="@{() -> productDetailViewModel.onAddButtonClicked(quantityNumber.text)}"
但编译时始终报错:
error: cannot find symbol import com.example.checkoutexample.databinding.FragmentProductDetailBindingImpl; ^ symbol: class FragmentProductDetailBindingImpl location: package com.example.checkoutexample.databinding
布局代码
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" tools:context=".ProductDetailFragment"> <data> <variable name="productDetailViewModel" type="com.example.checkoutexample.ProductDetailViewModel" /> </data> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <ImageView android:id="@+id/productImage" android:layout_width="match_parent" android:layout_height="300dp" android:layout_gravity="center" android:scaleType="centerCrop" android:src="@drawable/cupcake" tools:src="@tools:sample/backgrounds/scenic" /> <TextView android:id="@+id/productTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/margin_small" android:layout_marginTop="@dimen/margin_small" android:text="@string/hazelnut_cupcakes" android:textSize="30sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/margin_medium" android:orientation="horizontal"> <TextView android:id="@+id/productPrice" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/margin_small" android:text="@string/product_price" android:textSize="20sp" /> <TextView android:id="@+id/stockCountMessage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/margin_medium" android:textColor="@{productDetailViewModel.remainingStock == 0 ? @color/red : @color/blue}" android:textSize="15sp" android:textStyle="italic" android:text="@{productDetailViewModel.remainingStock == 0 ? @string/out_of_stock : @string/stock_msg(productDetailViewModel.remainingStock)}" tools:text="(5 items left)" /> </LinearLayout> <TextView android:id="@+id/productDescription" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/margin_small" android:layout_marginTop="@dimen/margin_small" android:text="@string/product_description" /> <TextView android:id="@+id/quantityLabel" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="@dimen/margin_small" android:layout_marginTop="@dimen/margin_small" android:text="@string/quantity" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <EditText android:id="@+id/quantityNumber" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/margin_small" android:ems="2" android:gravity="center" android:inputType="number" android:minWidth="48dp" android:minHeight="48dp" android:text="@string/quantity_1" /> <Button android:id="@+id/addToCartButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/margin_small" android:enabled="@{productDetailViewModel.remainingStock == 0 ? false : true}" android:onClick="@{() -> productDetailViewModel.onAddButtonClicked(quantityNumber.getText())}" android:text="@string/add" /> </LinearLayout> <Button android:id="@+id/checkoutButton" android:layout_width="@dimen/button_width" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="@dimen/margin_large" android:text="@{@string/checkout(productDetailViewModel.orderTotal)}" android:textSize="20sp" /> </LinearLayout> </ScrollView> </layout>
Fragment代码
class ProductDetailFragment : Fragment() { private var _binding: FragmentProductDetailBinding? = null private val binding get() = _binding!! private lateinit var viewModel: ProductDetailViewModel private var stockLeft = 0 override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = FragmentProductDetailBinding.inflate(inflater, container, false) val view = binding.root viewModel = ViewModelProvider(this)[ProductDetailViewModel::class.java] binding.apply { productDetailViewModel = viewModel lifecycleOwner = viewLifecycleOwner viewModel.orderTotal.observe(viewLifecycleOwner) { orderTotal -> with(checkoutButton) { setOnClickListener { val action = ProductDetailFragmentDirections.actionProductDetailFragmentToShoppingCartFragment( orderTotal ) view.findNavController().navigate(action) } } } viewModel.insufficientStock.observe(viewLifecycleOwner) { insufficientStock -> if (insufficientStock) { Toast.makeText( context, getString(R.string.low_stock_error, viewModel.remainingStock.value), Toast.LENGTH_LONG ).show() } } addToCartButton.setOnClickListener { // Would like to replace these two lines with DataBinding // val orderQuantity = quantityNumber.text.toString().toInt() // viewModel.onAddButtonClicked(orderQuantity) hideKeyboard(view) } } return view } private fun hideKeyboard(view: View) { val inputMethodManager = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0) } }
解决步骤
1. 修正DataBinding表达式的类型转换
ViewModel的onAddButtonClicked方法需要接收Int类型参数,但EditText的text属性返回的是Editable,直接传递会导致类型不兼容,这是编译失败的核心原因。修改Button的onClick表达式:
android:onClick="@{() -> productDetailViewModel.onAddButtonClicked(quantityNumber.text.isEmpty() ? 1 : Integer.parseInt(quantityNumber.text.toString()))}"
这段代码会先判断输入是否为空,为空则默认传1,否则把文本转成Int传递。
2. 移除Fragment中重复的点击监听
Fragment里手动给addToCartButton设置的点击监听会覆盖DataBinding的绑定逻辑,导致DataBinding的点击事件不生效,直接删除这段代码:
addToCartButton.setOnClickListener { // Would like to replace these two lines with DataBinding // val orderQuantity = quantityNumber.text.toString().toInt() // viewModel.onAddButtonClicked(orderQuantity) hideKeyboard(view) }
如果需要隐藏键盘,可以把hideKeyboard逻辑移到ViewModel的onAddButtonClicked方法中,或者通过BindingAdapter实现点击时隐藏键盘的通用逻辑。
3. 清理编译缓存并重新构建
BindingImpl类找不到通常是编译缓存问题,执行以下操作:
- 点击Android Studio顶部菜单栏的
Build->Clean Project - 再点击
Build->Rebuild Project - 若仍未解决,删除项目根目录下的
.gradle文件夹和模块内的build文件夹,然后重新编译
4. 确认ViewModel方法参数类型
确保ProductDetailViewModel中的onAddButtonClicked方法参数为Int类型:
fun onAddButtonClicked(quantity: Int) { // 处理添加购物车的业务逻辑 // 若需要隐藏键盘,可通过Context调用隐藏方法 }
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

