Как я могу выполнить привязку данных с живыми данными?
activity_user_detail.xml:
<data>
<variable
name = "viewModel"
type = "com.test.viewmodel.UserViewModel" />
</data>
<TextView
android:id = "@+id/tv_amount"
android:layout_width = "match_parent"
android:text = "@{viewModel.age}"
....
UserViewModel.java:
public class UserViewModel extends ViewModel {
public LiveData<User> user;
public void getUserById(UserDao userDao, String userId){
transaction = UserDao .load(userId);
}
}
UserDao.java:
@Query("SELECT * FROM `user` WHERE id = :userId")
LiveData<User> load(String userId);
UserDetailActivity.java:
private ActivityUserDetailBinding binding;
binding = DataBindingUtil.setContentView(this, R.layout.activity_user_detail);
viewModel = ViewModelProviders.of(this).get(UserViewModel.class);
viewModel.getUserById(userDao, userId);
viewModel.user.observe(this, user -> binding.setViewModel(user)); // How to bind livedata?
Я тоже пробовал это:
binding.setViewModel(viewModel);
@EpicPandaForce Извините, я не понимаю, что вы имеете в виду.
Они добавили поддержку привязки данных liveata только в последних версиях. Думаю, это была 1.1.1? см. developer.android.com/reference/android/databinding/…
Можно использовать привязку данных с LiveData <User>, но вы должны преобразовать User в int или String, чтобы использовать привязку данных. В противном случае пользовательский интерфейс не обновляется. Я задавал этот вопрос где-то здесь или на Reddit. Я могу написать подробный ответ, если вы не можете понять, когда я буду свободен.
да, я использую 1.1.1, но setLifecycleOwner не может быть разрешен.
@Thracian, может быть, какой-нибудь образец кода в качестве ответа?
@Alvin, он тоже работает с пользователем, но это должен быть новый пользователь. Я напишу ответ в ближайшее время без Room. Вы можете легко преобразовать его, если он не будет работать с Room, я тоже могу обновить ответ с помощью Room, но я занят изучением Dagger и довольно перегружен.
Это пример того, как работают LiveData и ObservableField. Вам нужно изменить объект T и setValue () с помощью LiveData или установить (T) с помощью ObservableField. Изменение свойств объекта T не приводит к обновлению пользовательского интерфейса.
<?xml version = "1.0" encoding = "utf-8"?>
<layout xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:app = "http://schemas.android.com/apk/res-auto">
<data>
<variable
name = "viewModel"
type = "com.example.tutorial3livedata_databinding2objects.UserViewModel" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width = "match_parent"
android:layout_height = "match_parent">
<TextView
android:id = "@+id/user_info"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:text='@{viewModel.userMutableLiveData.name+ ", email " + viewModel.userMutableLiveData.email}'
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintHorizontal_bias = "0.501"
app:layout_constraintLeft_toLeftOf = "parent"
app:layout_constraintRight_toRightOf = "parent"
app:layout_constraintTop_toTopOf = "parent"
app:layout_constraintVertical_bias = "0.1" />
<EditText
android:id = "@+id/et_name"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_marginEnd = "8dp"
android:layout_marginStart = "8dp"
android:layout_marginTop = "48dp"
android:text = "@ = {viewModel.userMutableLiveData.name}"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintHorizontal_bias = "0.501"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/user_info" />
<EditText
android:id = "@+id/et_email"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_marginEnd = "8dp"
android:layout_marginStart = "8dp"
android:layout_marginTop = "28dp"
android:text = "@ = {viewModel.userMutableLiveData.email}"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintHorizontal_bias = "0.501"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/et_name" />
<Button
android:id = "@+id/button_change_name"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_marginTop = "32dp"
android:onClick = "@{() -> viewModel.changeUserName()}"
android:text = "Change Name"
app:layout_constraintEnd_toStartOf = "@+id/button_change_user"
app:layout_constraintHorizontal_chainStyle = "spread"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/et_email" />
<Button
android:id = "@+id/button_change_user"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:onClick = "@{() -> viewModel.changeUser()}"
android:text = "Change User"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toEndOf = "@+id/button_change_name"
app:layout_constraintTop_toTopOf = "@+id/button_change_name" />
<Button
android:id = "@+id/button"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_marginTop = "56dp"
android:text = "Display User"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/button_change_name" />
</android.support.constraint.ConstraintLayout>
</layout>
ViewModel
public class UserViewModel extends ViewModel {
public MutableLiveData<User> userMutableLiveData = new MutableLiveData<>();
private User mUser;
public UserViewModel() {
mUser = new User("User", "[email protected]");
userMutableLiveData.setValue(mUser);
}
public void changeUserName() {
// Both updates LiveData but does not update UI
mUser.setName("Name is Changed");
// userMutableLiveData.getValue().setName("Updated Name");
// This one Updates UI
// userMutableLiveData.setValue(userMutableLiveData.getValue());
}
public void changeUser() {
mUser = new User("New User Name", "[email protected]");
// Without setting new value UI is not updated and observe is not called
userMutableLiveData.setValue(mUser);
}
}
Основная деятельность
/*
Without binding.setLifecycleOwner(this), liveData.setValue() does not update UI
liveData.setValue() updates UI
EditText changes LiveData but does not update UI
*/
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
UserViewModel userViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
// LiveData should call setValue() to update UI via binding
binding.setViewModel(userViewModel);
// Required to update UI with LiveData
binding.setLifecycleOwner(this);
}
}
Этот код предназначен для учебных целей.
Результаты, которые вы можете получить из этого кода:
1- Изменение имени пользователя с помощью changeUserName () обновляет имя существующего пользователя LiveData, но не обновляет пользовательский интерфейс. Пользовательский интерфейс обновляется при повороте устройства.
2- Когда вы меняете пользователя LiveData и работает привязка данных setValue ().
3- Изменение свойств пользователя с помощью двусторонней привязки EditText android:text = "@ = {viewModel.userMutableLiveData.name}" изменяет имя пользователя LiveData, но не обновляет пользовательский интерфейс до тех пор, пока устройство не будет повернуто, поскольку пользователь остается прежним.
setLifecycleOwner не может быть найден.
Вы расширяете AppcompatActivity? Какая у вас версия для supportLibrary?
@ Элвин, хорошо. Надеюсь, вы получили представление о том, как работает привязка данных и LiveData. Он тоже хорошо работает с Room, верно?
@ M.Smith Пользователь является исключительно объектом POJO. Вы отправляете его как данные внутри класса LiveData. LiveData - это класс, в котором есть наблюдения, состояние наблюдателей и данные для передачи.
Если вы не используете двустороннюю привязку, вы можете рассмотреть возможность сделать userMutableLiveData закрытым и добавить геттер для LiveData (скрывая интерфейс MutableLiveData).
добавление binding.lifecycleOwner = this устранило мою проблему с макетом xml, который не обновлялся при обновлении данных viewModel.
Ваша версия привязки данных + жизненного цикла актуальна