Android 使用数据绑定onClick表达式时未生成片段的BindingImpl类
在片段布局中,我有一个按钮,它使用XMLOnClick表达式调用相应ViewModel中的方法 问题是,在构建项目时,编译器会抛出以下错误:Android 使用数据绑定onClick表达式时未生成片段的BindingImpl类,android,gradle,data-binding,Android,Gradle,Data Binding,在片段布局中,我有一个按钮,它使用XMLOnClick表达式调用相应ViewModel中的方法 问题是,在构建项目时,编译器会抛出以下错误: error: cannot find symbol import com.aresid.myapp.databinding.FragmentLoginBindingImpl; ^ symbol: class FragmentLoginBindingImpl location: pa
error: cannot find symbol
import com.aresid.myapp.databinding.FragmentLoginBindingImpl;
^
symbol: class FragmentLoginBindingImpl
location: package com.aresid.myapp.databinding
问题是,当我从XML中的函数签名和函数调用中删除参数时,应用程序的构建不会出现问题
我的期望是,当我单击login按钮时,将调用ViewModel中的方法,记录emailField.text和passwordField.text
布局文件:
以及创建视图的片段:
试试这个:
用于您的电子邮件和密码。这样,用户在UI中更改ViewModel字段后,这些字段将自动更改:
android:text=@={viewmodel.password}
您的函数onLoginButtonClicked现在可以在没有参数的情况下声明。这些值现在作为ViewModel的字段保存,以便您可以在函数中自由获取它们
在xml中,还要更改onClick:
android:onClick=@{->loginViewModel.onLoginButtonClicked}
谢谢你的回答。不幸的是,它对我不起作用。我按照你上面写的那样做了,并使用了双向数据绑定。我还尝试了你链接中的BaseObservable功能。实际上,你可以使用当前的LiveData而不是Observable,但可能会将私有改为公共,数据绑定可以很好地使用它。你说它不起作用是什么意思?您仍然有相同的生成错误吗?你们可以阅读有关LiveData的官方文件中的第一篇文章有点过时了。哦,天哪。将LiveData从私有更改为公共确实解决了这个问题。在那之前,是的,我得到了同样的构建错误。无论如何,非常感谢你的帮助。
<?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="loginViewModel"
type="com.aresid.myapp.login.LoginViewModel"
/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/fragmentPaddingMedium"
tools:context=".login.LoginFragment"
>
<ImageView
android:id="@+id/app_logo"
android:layout_width="@dimen/imageViewAppLogoSize"
android:layout_height="@dimen/imageViewAppLogoSize"
android:layout_marginTop="4dp"
android:contentDescription="@string/my_app_logo"
android:src="@drawable/my_app_logo_144"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/email_field_layout"
style="@style/Widget.MyApp.TextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorEnabled="true"
app:layout_constraintTop_toBottomOf="@+id/app_logo"
>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/email_field"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/email"
android:inputType="textEmailAddress"
android:maxLines="1"
android:singleLine="true"
/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_field_layout"
style="@style/Widget.MyApp.TextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorEnabled="true"
app:layout_constraintTop_toBottomOf="@+id/email_field_layout"
app:passwordToggleEnabled="true"
>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password_field"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password"
android:imeActionId="6"
android:imeActionLabel="@string/common_signin_button_text"
android:imeOptions="actionUnspecified"
android:inputType="textPassword"
android:maxLines="1"
android:singleLine="true"
/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/login_button"
style="@style/Widget.MyApp.ContainedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/log_in"
android:onClick="@{() -> loginViewModel.onLoginButtonClicked(emailField.text, passwordField.text)}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/password_field_layout"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="13dp"
android:text="@string/sign_up_using_these_colon"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="@+id/signup_button_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
<LinearLayout
android:id="@+id/signup_button_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="13dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/email_signup_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6.5dp"
android:background="@drawable/round_button_background"
android:src="@drawable/ic_email_24dp"
/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/google_signup_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6.5dp"
android:background="@drawable/round_button_background"
android:src="@drawable/ic_google_favicon_24dp"
/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
package com.aresid.myapp.login
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import timber.log.Timber
/**
* Created on: 27/04/2020
* For Project: MyApp
* Author: René Spies
* Copyright: © 2020 ARES ID
*/
class LoginViewModel: ViewModel() {
// LiveData for the login email
private val _email = MutableLiveData<String>()
val email: LiveData<String>
get() = _email
// LiveData for the login password
private val _password = MutableLiveData<String>()
val password: LiveData<String>
get() = _password
// LiveData for the login button
private val _wantLogin = MutableLiveData<Boolean>()
val wantLogin: LiveData<Boolean>
get() = _wantLogin
init {
Timber.d("init: called")
// TODO: init: init objects here
// Init email LiveData
_email.value = ""
// Init password LiveData
_password.value = ""
// Init wantLogin LiveData
_wantLogin.value = false
}
fun onLoginButtonClicked(email: String, password: String) {
Timber.d("onLoginButtonClicked: called")
Timber.d("email = $email\npassword = $password")
// TODO: onLoginButtonClicked: log in user
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
Timber.d("onCreateView: called")
// Define LoginViewModel
loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java)
// Define FragmentLoginBinding and inflate the layout
binding = FragmentLoginBinding.inflate(inflater, container, false)
// TODO: onCreateView: code goes here
// Let the data binder know about the LoginViewModel
binding.loginViewModel = loginViewModel
// Return the inflated layout
return binding.root
}