Как я могу выполнить привязку данных с живыми данными?

Как я могу выполнить привязку данных с живыми данными?

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 11.07.2018 16:36

@EpicPandaForce Извините, я не понимаю, что вы имеете в виду.

Alvin 11.07.2018 16:38

Они добавили поддержку привязки данных liveata только в последних версиях. Думаю, это была 1.1.1? см. developer.android.com/reference/android/databinding/…

EpicPandaForce 11.07.2018 16:41

Можно использовать привязку данных с LiveData <User>, но вы должны преобразовать User в int или String, чтобы использовать привязку данных. В противном случае пользовательский интерфейс не обновляется. Я задавал этот вопрос где-то здесь или на Reddit. Я могу написать подробный ответ, если вы не можете понять, когда я буду свободен.

Thracian 11.07.2018 16:53

да, я использую 1.1.1, но setLifecycleOwner не может быть разрешен.

Alvin 11.07.2018 16:53

@Thracian, может быть, какой-нибудь образец кода в качестве ответа?

Alvin 11.07.2018 16:54

@Alvin, он тоже работает с пользователем, но это должен быть новый пользователь. Я напишу ответ в ближайшее время без Room. Вы можете легко преобразовать его, если он не будет работать с Room, я тоже могу обновить ответ с помощью Room, но я занят изучением Dagger и довольно перегружен.

Thracian 11.07.2018 16:59
11
7
12 813
1

Ответы 1

Это пример того, как работают 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 не может быть найден.

Alvin 12.07.2018 07:51

Вы расширяете AppcompatActivity? Какая у вас версия для supportLibrary?

Thracian 12.07.2018 07:53

@ Элвин, хорошо. Надеюсь, вы получили представление о том, как работает привязка данных и LiveData. Он тоже хорошо работает с Room, верно?

Thracian 12.07.2018 16:18

@ M.Smith Пользователь является исключительно объектом POJO. Вы отправляете его как данные внутри класса LiveData. LiveData - это класс, в котором есть наблюдения, состояние наблюдателей и данные для передачи.

Thracian 25.05.2019 19:56

Если вы не используете двустороннюю привязку, вы можете рассмотреть возможность сделать userMutableLiveData закрытым и добавить геттер для LiveData (скрывая интерфейс MutableLiveData).

jeubank12 25.07.2019 20:04

добавление binding.lifecycleOwner = this устранило мою проблему с макетом xml, который не обновлялся при обновлении данных viewModel.

SmellydogCoding 23.11.2020 22:09

Другие вопросы по теме