Google SignInButton's onClick doesn't work using DataBinding

匿名 (未验证) 提交于 2019-12-03 01:45:01

问题:

When I try to set the onClick method in my Google's SignInButton:

android:onClick="@{() -> viewModel.onGoogleLoginClick()}"

I always get this error:

Found data binding errors.

****/ data binding error ****msg:Cannot find the proper callback class for android:onClick. Tried android.view.View but it has 0 abstract methods, should have 1 abstract methods.

file:/Users/user/Android/project/app/src/main/res/layout/activity_login.xml loc:53:31 - 53:66 ****\ data binding error ****

Here is my code:

activity_login.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"     tools:context=".ui.login.LoginActivity">     <data>         <import type="android.view.View" />         <variable             name="viewModel"             type="com.example.myapp.ui.login.LoginViewModel" />     </data>      <RelativeLayout         android:layout_width="match_parent"         android:layout_height="match_parent"         android:gravity="center_horizontal"         android:orientation="vertical"         android:padding="@dimen/default_layout_padding">          <EditText             android:id="@+id/login_name_editText"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:hint="@string/login_username_hint"             android:inputType="text"             android:text="@{viewModel.mEmail}" />          <EditText             android:id="@+id/login_pass_editText"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_below="@+id/login_name_editText"             android:hint="@string/login_password_hint"             android:inputType="numberPassword"             android:text="@{viewModel.mPassword}" />          <Button             android:id="@+id/login_login_button"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_below="@+id/login_pass_editText"             android:onClick="@{() -> viewModel.onServerLoginClick()}"             android:text="@string/login_login_button_text"             android:textAllCaps="true" />          <com.google.android.gms.common.SignInButton             android:id="@+id/login_google_button"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_below="@+id/login_login_button"             android:onClick="@{() -> viewModel.onGoogleLoginClick()}"/>     </RelativeLayout> </layout> 

LoginViewModel.class

public class LoginViewModel extends BaseViewModel<LoginNavigator> implements         GoogleApiClient.OnConnectionFailedListener, OnCompleteListener<GoogleSignInAccount>,         GoogleApiClient.ConnectionCallbacks {      private static final String LOG_TAG = LoginViewModel.class.getSimpleName();      public String mEmail;     public String mPassword;      public LoginViewModel(DataManager dataHelper, SchedulerProvider schedulerProviderHelper) {         super(dataHelper, schedulerProviderHelper);     }      public void onServerLoginClick() {         if (CommonUtils.loginDataIsCorrect(mEmail, mPassword)) {             doServerLogin(mEmail, mPassword);         } else {             getNavigator().handleError();         }     }      public void onGoogleLoginClick() {         getNavigator().googleLogin();     }      // Server     private void doServerLogin(String name, String pass) {         ...     }      // Google     protected void doGoogleLogin(FragmentActivity fragmentActivity, Context context) {         ...     }     ... } 

LoginActivity.class

public class LoginActivity extends BaseActivity<ActivityLoginBinding, LoginViewModel> implements LoginNavigator {      private static final int REQUEST_CODE_REGISTER = 0;     private static final int REQUEST_CODE_GOOGLE_SIGN_IN = 1;      @BindString(R.string.login_data_missing_message)     String mDataMissingMessage;      @Inject     LoginViewModel mLoginViewModel;     private ActivityLoginBinding mActivityLoginBinding;      public static Intent newIntent(Context context) {         return new Intent(context, LoginActivity.class);     }      @Override     public int getBindingVariable() {         return BR.viewModel;     }      @Override     public int getLayoutId() {         return R.layout.activity_login;     }      @Override     public LoginViewModel getViewModel() {         return mLoginViewModel;     }      @Override     protected void onCreate(@Nullable Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_login);         mActivityLoginBinding = getViewDataBinding();          mLoginViewModel.setNavigator(this);         mActivityLoginBinding.loginGoogleButton.setSize(SignInButton.SIZE_WIDE);     }      @Override     protected void onActivityResult(int requestCode, int resultCode, Intent data) {         switch (requestCode) {             case REQUEST_CODE_GOOGLE_SIGN_IN:                 mLoginViewModel.handleGoogleSignInResult(data);                 break;         }         super.onActivityResult(requestCode, resultCode, data);     }      @Override     public void googleLogin() {         mLoginViewModel.doGoogleLogin(this, this);     }      @Override     public void showGoogleForm(GoogleApiClient googleApiClient) {         Intent googleIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient);         startActivityForResult(googleIntent, REQUEST_CODE_GOOGLE_SIGN_IN);     }     ... } 

And the BaseActivity.class, where I bind view and data for each Activity:

public abstract class BaseActivity<T extends ViewDataBinding, V extends BaseViewModel> extends AppCompatActivity {      private T mViewDataBinding;     private V mViewModel;      public abstract int getBindingVariable();      @LayoutRes     public abstract int getLayoutId();      public T getViewDataBinding() {         return mViewDataBinding;     }      public abstract V getViewModel();      public void performDependencyInjection() {         AndroidInjection.inject(this);     }      @Override     protected void onCreate(@Nullable Bundle savedInstanceState) {         performDependencyInjection();         super.onCreate(savedInstanceState);         performDataBinding();     }      @Override     protected void onResume() {         super.onResume();     }      private void performDataBinding() {         mViewDataBinding = DataBindingUtil.setContentView(this, getLayoutId());         this.mViewModel = mViewModel == null ? getViewModel() : mViewModel;         mViewDataBinding.setVariable(getBindingVariable(), mViewModel);         mViewDataBinding.executePendingBindings();     } } 

Does anyone know why this error? Because SignInButton implements OnClickListener. I have tried Invalidate Caches / Restart and deleting .gradle and .idea folders but is still not working.

回答1:

It's a interesting question, since SignInButton extends View, but the doc states explicitly to register a listener with setOnClickListener(OnClickListener) in the class and not in the xml. Databinding wraps up the lamda expression as a listener (you can see that in the auto-generated data binding class) and probably it doesn't stick with the listener, which SignInButton is expecting. E.g. if you try to pass a View.OnClickListener variable via xml, you shouldn't get that compile error, but you probably also won't be able to receive your click events (like it's stated in the doc).



回答2:

Luckily, we've got @BindingAdapter to solve issues similar to this. Here's an example in Kotlin:

BindingAdapters.kt

@BindingAdapter("android:onClick") fun bindSignInClick(button: SignInButton, method: () -> Unit) {     button.setOnClickListener { method.invoke() } } 

layout.xml

<com.google.android.gms.common.SignInButton             ...             android:onClick="@{() -> viewModel.onSignInClick()}" /> 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!