Значения поля ViewModel не отображаются в привязанном элементе управления пользовательского интерфейса - PullRequest
0 голосов
/ 30 мая 2020

У меня есть класс ViewModel, содержащий список вопросов и текущий вопрос, отображаемый на экране. Когда пользователь нажимает кнопку (в данном случае «Да»), поле текущего вопроса обновляется путем обновления индекса. Я использую привязку данных для привязки ViewModel к фрагменту. Вот мой QuestionViewModel класс:

package com.example.self_care.vm;

import com.example.self_care.data.QuestionsRepository;
import com.example.self_care.data.models.Question;
import com.example.self_care.util.Injector;

import java.util.List;
import java.util.Objects;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class QuestionViewModel extends ViewModel {
    private LiveData<List<Question>> questions;
    private MutableLiveData<Integer> currentIndex = new MutableLiveData<>(0);
    private MutableLiveData<Question> currQuestion = new MutableLiveData<>();
    private QuestionsRepository questionsRepository;

    QuestionViewModel(QuestionsRepository repository){
        this.questionsRepository = repository;

        this.questions = this.questionsRepository.getQuestions();
    }

    public LiveData<List<Question>> getQuestions() { return this.questions;}
    public MutableLiveData<Integer> getCurrentIndex(){ return this.currentIndex;}
    public MutableLiveData<Question> getCurQuestion(){ return this.currQuestion;}

    public void setCurrentIndex(int num){
        int idx = num % Objects.requireNonNull(questions.getValue()).size();
        this.currentIndex.setValue(idx);
        this.currQuestion.setValue(this.questions.getValue().get(idx));
    }

}

QuestionFragment класс, к которому привязана ViewModel:

package com.example.self_care.ui.main;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.self_care.R;
import com.example.self_care.databinding.FragmentQuestionBinding;
import com.example.self_care.util.Injector;
import com.example.self_care.vm.QuestionViewModel;
import com.example.self_care.vm.QuestionViewModelFactory;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;

public class QuestionFragment extends Fragment {

    private QuestionViewModel questionViewModel;

    public static QuestionFragment newInstance() {
        return new QuestionFragment();
    }

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

        QuestionViewModelFactory factory = Injector.provideQuestionViewModelFactory(getActivity());
        questionViewModel = new ViewModelProvider(this, factory).get(QuestionViewModel.class);

        this.questionViewModel.getQuestions().observe(this, questions -> {
            this.questionViewModel.setCurrentIndex(0);
        });

       FragmentQuestionBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_question, container, false);
       binding.setViewModel(questionViewModel);

       binding.yesBtn.setOnClickListener(view -> {
           int idx = questionViewModel.getCurrentIndex().getValue();
           questionViewModel.setCurrentIndex(idx + 1);
       });

       return binding.getRoot();
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

}

И ресурс ui фрагмента:

<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">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        android:orientation="vertical"
        tools:context=".ui.main.QuestionActivity"
        tools:ignore="MergeRootFrame">

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:fitsSystemWindows="true">

            <com.google.android.material.appbar.CollapsingToolbarLayout
                android:id="@+id/toolbar_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                app:title="@{viewModel.curQuestion.feedbackTitle}"
                app:toolbarId="@+id/toolbar">

                <androidx.appcompat.widget.Toolbar
                    android:id="@+id/detail_toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

            </com.google.android.material.appbar.CollapsingToolbarLayout>

        </com.google.android.material.appbar.AppBarLayout>

        <TextView
            android:id="@+id/question_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="32dp"
            android:layout_marginTop="16dp"
            android:text="@{viewModel.curQuestion.title}" />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <Button
                android:id="@+id/yes_btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="52dp"
                android:layout_marginEnd="32dp"
                android:layout_marginTop="32dp"
                android:text="@string/yes"/>

            <Button
                android:id="@+id/no_btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="52dp"
                android:layout_marginTop="32dp"
                android:text="@string/no" />
        </LinearLayout>


    </LinearLayout>

    <data>

        <variable
            name="viewModel"
            type="com.example.self_care.vm.QuestionViewModel" />
    </data>

</layout>

Отлаживая код, я вижу, что нажатие на кнопку Yes обновляет currentIndex, а это, в свою очередь, обновляет currentQuestion. Однако я ничего не вижу на экране, то есть значения TextView компонентов пусты. Как я могу решить эту проблему и сделать так, чтобы значения вопросов отображались на экране? родительская активность?

РЕДАКТИРОВАТЬ: после установки binding.setLifecycleOwner(this) в QuestionFragment вопрос отображается в представлении. Теперь, когда пользователь нажимает кнопку Yes, он обновляет вопрос, но также создает еще одну кнопку Yes. Что странно. См. Рисунок ниже

Screenshot

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...