Приложение использует фрагменты в сочетании с шаблоном View Model. Во фрагменте будут отображены два Spinners и RecylclerView. Один из Spinner содержит день недели с соответствующими упражнениями, которые должны быть обновлены при изменении выбора дня Spinner. Поэтому я использую метод Livedata.observe()
. В начале приложения будут загружены все упражнения текущего дня. Кроме того, к упражнениям будет добавлен еще один элемент в этот список, чтобы создать новое упражнение (теперь я буду называть этот элемент «Добавить упражнение»).
Когда я теперь изменю день недели на другой день, списокбудет обновляться только после того, как я поверну экран. Кроме того, каждый раз, когда экран поворачивается, добавляется дополнительный пункт «Добавить упражнение». Основываясь на этом поведении, я понял, что метод onItemSelected()
в Spinner Listener будет активироваться при каждом повороте экрана, даже если не было взаимодействия с элементом Spinner.
Кроме того, все загруженные данные ивыбор элементов Spinner будет потерян, если я перейду на другой фрагмент (как я понял ViewModel, это именно то, что следует предотвратить с помощью класса ViewModel).
Наконец, вот мои вопросы:
- Почему экран обновляется только после поворота экрана?
- Почему возникают вызовы onItemSelected () элемента Spinner после поворота экрана, даже если не былокакие-либо взаимодействия с элементом счетчика?
- Почему я теряю фрагмент или, точнее, данные ViewModel после переключения на другой фрагмент?
Извлечение из HomeViewModel:
public class HomeViewModel extends ViewModel {
private static final String TAG = "HomeViewModel";
private MutableLiveData<List<Exercise>> mExercises;
private MutableLiveData<List<TrainingPlan>> mTrainingPlans;
private MutableLiveData<Integer> calendarDay;
private TrainingPlan selectedTrainingPlan;
final Exercise addExercise = Exercise.builder().name("ADD EXERCISE").sets(null).build();
private List<TrainingPlan> trainingPlans;
private List<Exercise> currentExercises;
public HomeViewModel() {
mTrainingPlans = new MutableLiveData<>();
mExercises = new MutableLiveData<>();
TrainingsPlanDAO trainingsPlanDAO = new DummyTrainingsPlanDAO();
trainingPlans = trainingsPlanDAO.searchAll();
setSelectedTrainingPlanToDefaultTrainingPlan(trainingPlans);
currentExercises = getExercisesOfTheCurrentDay();
if(currentExercises.isEmpty()){
Log.i(TAG, "No Exercises for the current day!");
}
mTrainingPlans.setValue(trainingPlans);
mExercises.setValue(currentExercises);
//additional Exercise in the list for Add function of new Exercise
currentExercises.add(addExercise);
}
public LiveData<List<Exercise>> getExercises() {
return mExercises;
}
public Integer getCurrentDay(){ return getCalendarDay(); }
public LiveData<List<TrainingPlan>> getTrainingPlans(){ return mTrainingPlans; }
public void setmExercisesToDay(int day){
List<Exercise> exercises = getExercisesOfDay(day);
exercises.add(addExercise);
mExercises.setValue(exercises);
}
private void setSelectedTrainingPlan(TrainingPlan selectedTrainingPlan){
this.selectedTrainingPlan = selectedTrainingPlan;
}...
HomeFragment:
public class HomeFragment extends Fragment {
private HomeViewModel homeViewModel;
private ExerciseRecyclerViewAdapter exerciseAdapter;
private ArrayAdapter<CharSequence> weekdayAdapter;
private ArrayAdapter<TrainingPlan> trainingPlanAdapter;
View root;
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
homeViewModel =
ViewModelProviders.of(this).get(HomeViewModel.class);
root = inflater.inflate(R.layout.fragment_home, container, false);
initElements();
return root;
}
private void initElements(){
initWeekdaySpinner();
initTrainingPlanSpinner();
initRecylerView();
}
private void initWeekdaySpinner(){
final Spinner currentDaySpinner = root.findViewById(R.id.currentDay_spinner);
currentDaySpinner.setOnItemSelectedListener(countrySelected);
weekdayAdapter = ArrayAdapter.createFromResource(getActivity(), R.array.weekdays, android.R.layout.simple_spinner_item);
weekdayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
currentDaySpinner.setAdapter(weekdayAdapter);
currentDaySpinner.setSelection(mapWeekdayFromCalenderDayToSpinnerPosition(homeViewModel.getCurrentDay()));
}
private void initTrainingPlanSpinner(){
final Spinner trainingPlanSpinner = root.findViewById(R.id.currentPlan_spinner);
trainingPlanAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, homeViewModel.getTrainingPlans().getValue());
trainingPlanAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
trainingPlanSpinner.setAdapter(trainingPlanAdapter);
}
private void initRecylerView(){
final RecyclerView recyclerView = root.findViewById(R.id.exercise_recyclerView);
homeViewModel.getExercises().observe(this, new Observer<List<Exercise>>() {
@Override
public void onChanged(@Nullable List<Exercise> mExercises) {
exerciseAdapter.notifyDataSetChanged();
}
});
exerciseAdapter = new ExerciseRecyclerViewAdapter(getActivity(), homeViewModel.getExercises().getValue());
RecyclerView.LayoutManager linearLayoutManager = new LinearLayoutManager(this.getContext());
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(exerciseAdapter);
}
AdapterView.OnItemSelectedListener countrySelected = new AdapterView.OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
homeViewModel.setmExercisesToDay(mapWeekdayFromSpinnerPositionToCalenderDay(position));
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
};
private int mapWeekdayFromCalenderDayToSpinnerPosition(int integer){
return (integer + 5) % 7;
}
private int mapWeekdayFromSpinnerPositionToCalenderDay(int integer){
return (integer + 2) % 7;
}
}