gpt4 book ai didi

android - 如何在 MVVM Android 中使用数据绑定(bind)处理 ViewModel 中的 onClick 或 onTouch 类事件

转载 作者:行者123 更新时间:2023-12-03 10:12:25 24 4
gpt4 key购买 nike

我浏览了许多与 相关的博客。带有数据绑定(bind)的 MVVM 模型 .
由于与 ViewModel 的数据绑定(bind)使得编写 junit 测试用例变得容易。

我想知道,如何实现像 OnTouchListener 这样的监听器事件, OnClickListener , OnFocusChangeListener在 ViewModel 中进行数据绑定(bind),这将使编写单元测试用例变得容易。

我已经使用黄油刀库进行绑定(bind),并通过它执行 OnTouch事件,我的问题是,在 Activity 中实现监听器而不是在 ViewModel 中直接实现它是一种正确的方法吗?
请引用下面的带有 MVVM 结构的 LoginScreen 代码:

LoginActivityNew.java

public class LoginActivityNew extends AppCompatActivity {

@BindView(R.id.et_password)
AppCompatEditText etPassword;

private LoginViewModel loginViewModel;

ActivityLoginBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

binding = DataBindingUtil.setContentView(this, R.layout.activity_login);
loginViewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
binding.setViewModel(loginViewModel);
binding.setLifecycleOwner(this);

ButterKnife.bind(this);

binding.buttonLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Common common = new Common(getApplicationContext());
common.isInternetAvailable(LoginActivityNew.this, new Common.InternetStateListener() {
@Override
public void onNetworkStateObtain(boolean isAvailable) {
loginViewModel.getAuthenticateTokenData().observe(LoginActivityNew.this, new Observer<TokenResponse>() {
@Override
public void onChanged(@Nullable TokenResponse tokenResponse) {
if (tokenResponse != null) {
loginResponseHandler(tokenResponse, tokenResponse.getUserName(), tokenResponse.getPassword());
} else {
Log.d("jdhadd","TokenResponse == null");
}
}
});
}
});
}
});

}


private void loginResponseHandler(final TokenResponse tokenResponse, final String username, final String password) {
switch (tokenResponse.getState()) {
case ApiState.LOADING:
Log.d("testData","Loading");
break;
case ApiState.COMPLETED:

Log.d("testData","COMPLETED");
break;
case ApiState.FAILURE:
Log.d("testData","FAILURE");

break;
default:
}
}

@OnClick(R.id.et_user_name)
void onTouchUserName() {
loginViewModel.resetEditTextField("username");
}

@OnClick(R.id.et_password)
void onTouchPassword() {
loginViewModel.resetEditTextField("password");
}
}

LoginViewModel.java
public class LoginViewModel extends AndroidViewModel {


public final MutableLiveData<String> userName = new MutableLiveData<>();
public final MutableLiveData<String> password = new MutableLiveData<>();
public final MutableLiveData<String> userNameError = new MutableLiveData<>();
public final MutableLiveData<String> passwordError = new MutableLiveData<>();
public final MutableLiveData<Boolean> userNameErrorVisibility = new MutableLiveData<>();
public final MutableLiveData<Boolean> passwordErrorVisibility = new MutableLiveData<>();
public final MutableLiveData<Boolean> isViewPasswordIconVisible = new MutableLiveData<>();

private MutableLiveData<TokenResponse> tokenResponse;
private Application application;

public LoginViewModel(@NonNull Application application) {
super(application);
this.application = application;
}

public boolean isValidData() {
boolean isValid = true;

Log.d("fekjfnew","email = "+userName.getValue()+",, pass = "+password.getValue());

if (userName.getValue() == null || userName.getValue().equals("")) {

userNameError.setValue("Invalid Email");
isValid = false;
userNameErrorVisibility.setValue(true);

} else {
userNameError.setValue(null);
userNameErrorVisibility.setValue(false);
}

if (password.getValue() == null || password.getValue().equals("")) {
passwordError.setValue("Password too short");
passwordErrorVisibility.setValue(true);
isValid = false;

} else {
passwordError.setValue(null);
passwordErrorVisibility.setValue(false);
}

return isValid;
}


public MutableLiveData<TokenResponse> getAuthenticateTokenData() {
tokenResponse = new MutableLiveData<>();
if(isValidData()) {
// Call Repository to Perform API operation
}
return tokenResponse;
}





public void setPasswordIcon(boolean isVisible) {
isViewPasswordIconVisible.setValue(isVisible);
}

public void resetEditTextField(String filedName) {

if(filedName.equals("username"))
userNameErrorVisibility.setValue(false);
else if(filedName.equals("password"))
passwordErrorVisibility.setValue(false);
}
}

activity_login_new.xml
<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"
tools:context="com.test.views.activities.LoginActivityNew">

<data>
<import type="android.view.View"/>
<variable name="viewModel" type="com.test.viewModels.LoginViewModel"/>

</data>

<LinearLayout
android:padding="40dp"
android:orientation="vertical"
android:id="@+id/cl_login"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#4">


<android.support.v7.widget.AppCompatTextView
android:id="@+id/tv_sign_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_sign_in"
android:textColor="@color/colorWhite"
android:textSize="@dimen/login_header_text_size"
android:layout_marginTop="50dp"
/>

<android.support.v7.widget.AppCompatEditText
android:id="@+id/et_user_name"
android:layout_width="match_parent"
style="@style/LoginEditTextViewStyle"
android:layout_marginTop="10dp"
android:background="@{viewModel.userNameErrorVisibility ? @drawable/bg_error_edit_text : @drawable/bg_edit_text}"
android:ems="10"
android:hint="@string/hint_username_email"
android:imeOptions="actionNext"
android:transitionName=""
android:inputType="textPersonName"
android:paddingStart="20dp"
android:paddingTop="10dp"
android:paddingEnd="20dp"
android:text="@={viewModel.userName}"
android:paddingBottom="10dp"
android:layout_height="@dimen/login_height_of_edit_text" />

<android.support.v7.widget.AppCompatTextView
android:id="@+id/tv_incorrect_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:text="@={viewModel.userNameError}"
android:textColor="@color/colorErrorText"
android:textSize="@dimen/wrong_entries_text_size"
android:visibility="@{viewModel.userNameErrorVisibility ? View.VISIBLE : View.GONE}"
/>

<android.support.design.widget.TextInputEditText
android:id="@+id/et_password"
android:layout_width="match_parent"
style="@style/LoginEditTextViewStyle"
android:layout_marginTop="30dp"
android:background="@{viewModel.passwordErrorVisibility ? @drawable/bg_error_edit_text : @drawable/bg_edit_text}"
android:ems="10"
android:text="@={viewModel.password}"
android:hint="@string/hint_password"
android:imeOptions="actionDone"
android:inputType="text"
android:paddingStart="20dp"
android:paddingTop="10dp"
android:paddingEnd="20dp"
android:paddingBottom="10dp"
android:layout_height="@dimen/login_height_of_edit_text" />


<android.support.v7.widget.AppCompatTextView
android:id="@+id/tv_incorrect_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:text="@={viewModel.passwordError}"
android:textColor="@color/colorErrorText"
android:textSize="@dimen/wrong_entries_text_size"
android:visibility="@{viewModel.passwordErrorVisibility ? View.VISIBLE : View.GONE}"
app:layout_constraintStart_toEndOf="@id/guideline_v1"
app:layout_constraintTop_toBottomOf="@id/et_password" />

<android.support.v7.widget.AppCompatButton
android:id="@+id/button_login"
android:layout_width="match_parent"
android:layout_marginBottom="20dp"
android:background="#FF077DB2"
android:text="@string/label_sign_in"
android:textAllCaps="false"
android:layout_height="@dimen/login_height_of_edit_text"
android:textColor="#ffffff" />

<LinearLayout
android:id="@+id/ll_finger_print"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/button_login">

<android.support.v7.widget.AppCompatImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_fingerprint" />

<android.support.v7.widget.AppCompatTextView
android:id="@+id/text_fingerprint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="@string/text_fingerprint_id"
android:textColor="@color/colorWhite"
android:textSize="@dimen/fingerprint_id_text_size"
app:layout_constraintStart_toEndOf="@id/guideline_v7"
app:layout_constraintTop_toBottomOf="@id/button_login" />
</LinearLayout>
</LinearLayout>

样式.xml
<style name="LoginEditTextViewStyle" parent="android:Theme">
<item name="android:paddingStart">20dp</item>
<item name="android:paddingEnd">20dp</item>
<item name="android:paddingTop">10dp</item>
<item name="android:paddingBottom">10dp</item>
<item name="android:textColor">@color/colorWhite</item>
<item name="android:textColorHint">@color/colorWhiteWithThirtyTransparency</item>
<item name="android:background">@drawable/bg_edit_text</item>
<item name="android:textSize">@dimen/login_edit_text_size</item>
</style>

最佳答案

首先,您的点击监听器的代码包含应用程序逻辑,不应该在 View 中,而是在 View 模型中(例如,您可以在 View 模型中添加一个名为 login() 的公共(public)方法并处理其中的登录逻辑) .

其次,为了将点击事件绑定(bind)到方法,您可以在布局的 XML 文件中执行此操作:

<android.support.v7.widget.AppCompatButton
android:id="@+id/button_login"
...
android:onClick="@{() -> viewModel.login()}" />

然后,在单元测试中,您可以调用方法 login()为了测试它。

另一方面,绑定(bind)在 XML 中不直接可用的回调,例如 OnTouch ,您可以创建适配器以使其可用:
object MyAdapters {

...

@JvmStatic
@BindingAdapter("onTouch")
fun setTouchListener(view: View, callback: () -> Boolean) {
view.setOnTouchListener { v, event -> callback() }
}
}

<android.support.v7.widget.AppCompatButton
android:id="@+id/button_login"
...
app:onTouch="@{() -> viewModel.methodThatReturnsABoolean()}" />

请注意,您无法获取 MotionEvent OnTouchListener 的值使用上面显示的代码。如果你需要它,那么你将不得不以不同的方式实现你的适配器:
object MyAdapters {

...

@JvmStatic
@BindingAdapter("onTouchListener")
fun setTouchListener(view: View, listener: OnTouchListener) {
view.setOnTouchListener(listener)
}
}

<android.support.v7.widget.AppCompatButton
android:id="@+id/button_login"
...
app:onTouchListener="@{viewModel.onTouchListener}" />

关于android - 如何在 MVVM Android 中使用数据绑定(bind)处理 ViewModel 中的 onClick 或 onTouch 类事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55926038/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com