Kav*_*a_p 7 android mvvm android-databinding android-mvvm android-viewmodel
我浏览了许多与带有数据绑定的 MVVM 模型相关的博客。由于与 ViewModel 的数据绑定使得编写 junit 测试用例变得容易。
我想知道,我怎么能实现监听器事件一样OnTouchListener,OnClickListener,OnFocusChangeListener在这将使容易编写单元测试用例视图模型数据绑定。
我已经使用黄油刀库进行绑定,并通过它执行OnTouch事件,我的问题是,这是在 Activity 中实现侦听器而不是直接在 ViewModel 中实现它的正确方法吗?
请参考以下代码以了解具有 MVVM 结构的 LoginScreen:
登录ActivityNew.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");
}
}
Run Code Online (Sandbox Code Playgroud)
登录ViewModel.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);
}
}
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
样式文件
<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>
Run Code Online (Sandbox Code Playgroud)
Jul*_*ñas 10
首先,您的点击监听器的代码包含应用程序逻辑,不应在视图中,而应在视图模型中(例如,您可以添加一个调用login()视图模型的公共方法并处理其中的登录逻辑)。
其次,为了将点击事件绑定到该方法,您可以在您的布局的 XML 文件中进行:
<android.support.v7.widget.AppCompatButton
android:id="@+id/button_login"
...
android:onClick="@{() -> viewModel.login()}" />
Run Code Online (Sandbox Code Playgroud)
然后,在单元测试中,您可以调用该方法login()以对其进行测试。
另一方面,要绑定在 XML 中不直接可用的回调,例如OnTouch,您可以创建适配器以使其可用:
object MyAdapters {
...
@JvmStatic
@BindingAdapter("onTouch")
fun setTouchListener(view: View, callback: () -> Boolean) {
view.setOnTouchListener { v, event -> callback() }
}
}
Run Code Online (Sandbox Code Playgroud)
object MyAdapters {
...
@JvmStatic
@BindingAdapter("onTouch")
fun setTouchListener(view: View, callback: () -> Boolean) {
view.setOnTouchListener { v, event -> callback() }
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,您无法使用上面显示的代码获取 的MotionEvent值OnTouchListener。如果你需要它,那么你将不得不以不同的方式实现你的适配器:
object MyAdapters {
...
@JvmStatic
@BindingAdapter("onTouchListener")
fun setTouchListener(view: View, listener: OnTouchListener) {
view.setOnTouchListener(listener)
}
}
Run Code Online (Sandbox Code Playgroud)
<android.support.v7.widget.AppCompatButton
android:id="@+id/button_login"
...
app:onTouch="@{() -> viewModel.methodThatReturnsABoolean()}" />
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12830 次 |
| 最近记录: |