Очевидно, есть наука о привязке данных в android, которую я явно не понимаю. Я продолжаю бороться с обновлением представлений с помощью фрагмента или модели представления, где некоторые вещи «просто работают», другие кажутся нефункциональными.
Я хочу отключить кнопку входа в систему, изменить ее текст и установить альфа после ее нажатия до Я получаю ответ API, затем меняю его обратно. Как вы можете себе представить, я не хочу, чтобы пользователь повторно отправлял запрос на аутентификацию. Предварительное связывание данных с фрагментом будет обрабатывать прослушиватель onClick (), и я либо использую butterknife для связывания элемента, либо вручную, используя findViewById (). В любом случае, когда я изменил вид, это было практически мгновенно. Теперь с привязкой данных это кажется случайным и в некоторых случаях очень медленным, в то время как другие кажутся мгновенными. Я не включаю код, который изменит его обратно, так как он не меняет вид в первую очередь.
При написании этого у меня снова и снова возникала одна и та же проблема, кнопка никогда не меняется. Наблюдатель во фрагменте вызывается (в журнале он отображается в порядке, в котором я ожидал, что он был вызван), но пользовательский интерфейс просто не обновляется. Я снова запустил его на эмуляторе, и, как ни странно, журнал наблюдателя не появляется намного позже, а затем вид обновляется, как и ожидалось, Сорта. Он не обновлялся, когда я нажимал на кнопку, но, по крайней мере, кнопка изменилась до того, как ответ API вернулся. Не то чтобы это было полезно, потому что время между нажатием кнопки и изменением пользовательского интерфейса по-прежнему можно быстро нажать. Я остановил приложение и снова запустил его, и я вернулся к исходной проблеме, он не обновлялся вообще. Между тестами не было внесено никаких изменений кода.
Я использую SingleLiveEvent без изменений из примеров архитектуры googles https://github.com/android/architecture-samples/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/SingleLiveEvent.java
activity_main_login <- это фрагмент, а не активность, но у меня нет рефакторинг это еще. Это усечено, поэтому может не работать без контейнера макета. </p>
<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="mainViewModel"
type="com.example.viewmodel.MainViewModel" />
</data>
...
<Button
android:id="@+id/btnLogin"
android:layout_width="135dp"
android:layout_height="47dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="16dp"
android:onClick="@{() -> mainViewModel.loginClicked()}"
android:text="@string/login"
android:textColor="#ffffff"
android:textStyle="bold"
android:background="#e05206"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fingerprintSwitch"
tools:layout_editor_absoluteX="101dp" />
....
</layout>
MainFragment
ActivityMainLoginBinding binding;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(TAG, "-> onCreateView()" );
super.onCreateView(inflater, container, savedInstanceState);
mainViewModel = new ViewModelProvider(this).get(MainViewModel.class);
getLifecycle().addObserver(mainViewModel);
binding = DataBindingUtil.inflate(inflater, R.layout.activity_main_login, container, false);
mView = binding.getRoot();
binding.setMainViewModel(mainViewModel);
binding.setLifecycleOwner(this); // Yeah this is what I forgot last time...
return mView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
AppLog.d(TAG, "-> onViewCreated()" );
super.onViewCreated(view, savedInstanceState);
mainViewModel.getShowLoading().observe(getViewLifecycleOwner(), showLoading -> {
AppLog.d(TAG, "showLoading changed");
this.loading = true;
binding.btnLogin.setText(R.string.loggingIn);
binding.btnLogin.setEnabled(false);
binding.btnLogin.setAlpha(.5f);
});
}
MainViewModel
private SingleLiveEvent<Boolean> showLoading = new SingleLiveEvent<>();
public void loginClicked() {
Log.d(TAG, "loginClicked()");
showLoading.setValue(true);
login();
}
Вот как выглядят журналы, когда он запускается и вы нажимаете кнопку входа ...
D/MainViewModel: loginClicked()
D/MainFragment: showLoading changed
D/MainViewModel: login()