Я пытаюсь создать простой экран «Вход в систему» с использованием шаблона MVVM.У меня есть двусторонняя привязка данных между моим View
и Model
классом, но что же остается для ViewModel
?
Первоначально я думал, что у меня даже не будет Model
class и my ViewModel
class будут иметь свойства для двустороннего связывания данных с View
, но класс ViewModel
уже расширяет класс, необходимый для его раздувания во Fragment, и, следовательно, не может расширятьсяBaseObservable
, чтобы разрешить двустороннюю привязку данных.
Я думаю, что в целом я запутался в том, как эти компоненты должны взаимодействовать друг с другом или что мне нужно / не нужно.
Мой фрагмент (просмотр)
public class LoginFragment extends Fragment {
private LoginViewModel mViewModel;
public static LoginFragment newInstance() {
return new LoginFragment();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
LoginFragmentBinding binding = LoginFragmentBinding.inflate(inflater, container, false);
binding.setViewModel(mViewModel); // mViewModel is null here...
binding.setLoginInfo(new LoginInfo());
return binding.getRoot();
}
}
И некоторые из моих login_fragment.xml
<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="viewModel" type="login.ui.LoginViewModel"/>
<variable name="loginInfo" type="login.ui.model.LoginInfo" />
</data>
<android.support.constraint.ConstraintLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".login.ui.LoginFragment">
<EditText
android:id="@+id/input_password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:autofillHints="password"
android:ems="10"
android:hint="@string/hint_password"
android:inputType="textPassword"
android:text="@={loginInfo.password}"
app:layout_constraintBottom_toTopOf="@id/button_sign_in"
app:layout_constraintEnd_toEndOf="@id/input_username"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@id/input_username"
app:layout_constraintTop_toBottomOf="@id/input_username" />
<EditText
android:id="@+id/input_username"
android:layout_width="350dp"
android:layout_height="wrap_content"
android:layout_marginTop="285dp"
android:autofillHints="username"
android:ems="10"
android:hint="@string/hint_username"
android:inputType="textEmailAddress"
android:text="@={loginInfo.username}"
app:layout_constraintBottom_toTopOf="@id/input_password"
app:layout_constraintEnd_toStartOf="@id/guideline"
app:layout_constraintStart_toStartOf="@id/guideline"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_sign_in"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/hint_sign_in"
android:onClick="@{()-> viewModel.onSignInClicked(loginInfo)}"
app:layout_constraintBottom_toTopOf="@id/button_create_account"
app:layout_constraintEnd_toEndOf="@id/input_password"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@id/input_password"
app:layout_constraintTop_toBottomOf="@id/input_password" />
Мой класс ViewModel
public class LoginViewModel extends ViewModel {
// Want to bind this to a button in the XML, but
// the mViewModel instance in the LoginFragment isnt assigned
public void onSignInClicked(LoginInfo info) {
Log.i("Username", info.getUsername());
Log.i("Password", info.getPassword());
// TODO: Actual log in attempt
}
}
Мой класс LoginInfo (модель)
public class LoginInfo extends BaseObservable {
private String username = "";
private String password = "";
@Bindable
public String getUsername() {
return username;
}
public void setUsername(String username) {
/*Listener will repeatedly call setPassword() every time it is notified,
avoid infinite loops*/
if (!this.username.equals(username)) {
Log.i("Username", username);
this.username = username;
notifyPropertyChanged(BR.username);
}
}
@Bindable
public String getPassword() {
return password;
}
public void setPassword(String password) {
/*Listener will repeatedly call setPassword() every time it is notified,
avoid infinite loops*/
if (!this.password.equals(password)) {
Log.i("Password", password);
this.password = password;
notifyPropertyChanged(BR.password);
}
}
}