У меня есть класс 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
. Что странно. См. Рисунок ниже