Автоматически сохранять изменения из двухсторонней привязки данных с помощью Room?

Вопрос

Двусторонняя привязка данных позволяет автоматически заполнять компоненты пользовательского интерфейса данными из объекта, а затем автоматически обновлять объект по мере того, как пользователь редактирует эти компоненты пользовательского интерфейса.

Когда пользователь редактирует компоненты пользовательского интерфейса, есть ли способ не только автоматически обновлять объект в памяти, но и автоматически обновлять / сохранять объект в базе данных комнаты?

Я мог вручную прослушивать каждое изменение поля пользовательского интерфейса и вручную сохранять объект в базе данных комнаты. Однако такой ручной подход грубой силы свел бы на нет преимущества двусторонних привязок данных, которые я надеюсь использовать.

Контекст

Мое приложение хранит элементы в базе данных SQLite с помощью библиотеки сохранения состояния комнаты Android. Это упрощенная версия моего предмета:

@Entity
public class Item {

    @PrimaryKey(autoGenerate = true)
    private long id;

    private String name;

    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Магия ViewModel, LiveData и двусторонних привязок данных позволяет моему ItemEditorFragment автоматически заполнять пользовательский интерфейс данными из выбранного элемента и обновлять этот элемент, когда пользователь редактирует компоненты пользовательского интерфейса:

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    if (context instanceof ItemViewModelProvider) {
        final ItemViewModelProvider itemViewModelProvider = (ItemViewModelProvider) context;
        mViewModel = itemViewModelProvider.getItemViewModel();
    } else {
        throw new RuntimeException(context.toString()
                + " must implement ItemViewModelProvider");
    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    final FragmentItemEditorBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_item_editor, container, false);
    binding.setViewModel(mViewModel);
    binding.setLifecycleOwner(this);

    final View view = binding.getRoot();
    return view;
}

Это упрощенная версия раздуваемого макета:

<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="viewModel"
            type="com.lafave.ItemViewModel" />
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@={viewModel.selectedItem.name}"
            android:layout_gravity="center_horizontal"/>

    </LinearLayout>
</layout>

person Ed LaFave    schedule 23.06.2018    source источник


Ответы (1)


Один из грязных приемов, которые я сделал, - это создание нового свойства в ViewModel (но оно не обязательно должно быть именно там) без вспомогательного поля (в Java это, вероятно, равносильно созданию получателя и сеттер без поля):

    var selectedItemName: String?

        get() = selectedItem.value?.name

        set(value) {
            selectedItem.value?.let {
                    it.name = value
                    dao.update(it)
                }
        }

Это не идеальное решение, поскольку оно требует зеркального отображения всех свойств в классе, но оно работает, если вы просто хотите покончить с этим. Я жду лучшего решения!

person Aleksandar Stefanović    schedule 17.03.2020