Android Java - Состояние гонки в OnCreate с двумя наблюдателями и составлением списков - PullRequest
0 голосов
/ 09 февраля 2020

извините, если это запутанный вопрос. Работая над созданием приложения для курса колледжа, я сталкиваюсь (как представляется) с состоянием гонки в моем методе OnCreate.

TL; DR - иногда мой счетчик заполняется, и я могу получить индекс из Это. Иногда он еще не заполняется при попытке получить указанный c индекс. Подробности и код ниже.

Приложение является «планировщиком курса» для студента колледжа.

Я создаю мероприятие, которое отображает информацию о существующем курсе и позволяет вам редактировать его. В методе OnCreate для этого занятия я заполняю счетчик для «Менторов» для курса и счетчик, для которого «Термин» входит в курс. Эта информация берется из БД комнаты.

У меня есть отдельное занятие для нового курса и для редактирования курса. Для "нового курса" деятельности все отлично работает. Я успешно получаюAllMentors () или getAllTerms () и заполняю список счетчиков.

Для действия «Редактировать курс» требуется дополнительный шаг, и он, кажется, вызывает у меня некоторые проблемы.

При редактировании курса я передаю намерение из исходной Деятельности со всеми необходимыми EXTRAS. Это успешно. В OnCreate для EditCourseActivity я делаю следующее:

  1. Я получаю mentorID из EXTRA, который передается из инициирующего Activity.
  2. Я обращаюсь к своему MentorViewModel и вызываю мой метод getAllMentors (), который возвращает LiveData> всех наставников в БД.
  3. , поскольку он возвращает LiveData, я использую наблюдателя и l oop через LiveData, добавляя имя каждого наставника в список, а всего наставника - в список.
  4. Я заполняю свой счетчик информацией в Списке, полным имен наставников.
  5. , затем я делаю для l oop, перебирая List, ища тот, у которого тот же идентификатор, что и у меня, полученный в EXTRA на шаге 1.
  6. Если я найду совпадение в В этом списке я вызываю метод getMentorName (), чтобы зацепить их имя в виде строки.
  7. У меня есть метод getIndex (spinner, string), который будет l oop через предоставленный счетчик, пытаясь найти совпадение для строки, которая передана (имя наставника), которую я взял, которая должна соответствовать идентификатору наставника, назначенного для курса. Этот метод возвращает местоположение индекса совпавшей строки в счетчике.
  8. Я установил выбор счетчика на найденный индекс.

Я делаю в основном тот же процесс для термина.

Я, как новый разработчик, не привык к тому, что OnCreate запускает код синхронно. Из-за этого, кажется, что у меня есть состояние гонки где-то между заполнением списка имен наставников, который заполняет счетчик, и вызовом моего метода getIndex ().
Иногда счетчик заполняется, и getIndex работает правильно и устанавливает правильный наставник , Иногда счетчик пуст, и мой метод getIndex () возвращает -1 (что он должен делать в ситуации отсутствия поиска), который заполняет счетчик первым элементом в списке (после его заполнения).

protected void onCreate(Bundle savedInstanceState) {
//////////////////////////Handling Mentor spinner menu/////////////////////////////////////////////////
        int mentorId = courseData.getIntExtra(EXTRA_COURSE_MENTOR_ID, -1);
        final ArrayAdapter<String> sp_CourseMentorAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, mentorNameList);
        sp_CourseMentorAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        sp_CourseMentor.setAdapter(sp_CourseMentorAdapter);

        final MentorViewModel mentorViewModel = ViewModelProviders.of(this).get(MentorViewModel.class);

        //Mentor test = mentorViewModel.getMentorById(mentorId);

        mentorViewModel.getAllMentors().observe(this, new Observer<List<Mentor>>() {
            @Override
            public void onChanged(@Nullable List<Mentor> mentorList) {
                if (mentorList != null) {
                    for (Mentor m : mentorList) {
                        mentorNameList.add(m.getMentor_name());
                        mentorListMentor.add(m);
                    }
                }
                sp_CourseMentorAdapter.notifyDataSetChanged();
            }
        });

        for(Mentor m: mentorListMentor){
            if (m.getMentor_id()==mentorId){
                String test = m.getMentor_name();
                int spinnerSelectionM2 = getIndexM(sp_CourseMentor, test);
                sp_CourseMentor.setSelection(spinnerSelectionM2);
            }
        }

Есть ли способ заставить их работать асинхронно? Каким-то образом, чтобы наблюдатель выполнил мой метод getAllMentors (), чтобы он сначала завершился и заполнил счетчик, ПОТОМ, чтобы запустить l oop?

Или лучший способ справиться с этим?

Заранее спасибо.

1 Ответ

0 голосов
/ 09 февраля 2020

Room всегда запускает код в отдельном потоке, а не в главном / пользовательском интерфейсе. Вы можете изменить это поведение с помощью

allowMainThreadQueries ()

после инициализации базы данных. Сначала будет запущен запрос, заполните ваш список, а затем запустите код for -l oop. Я не рекомендую такой подход, поскольку делать запросы в потоке пользовательского интерфейса - это плохая практика.

У вас есть два варианта:

  • Изменить свое значение l oop к функции и вызовите ее после добавления значений от наблюдателя:

    mentorViewModel.getAllMentors().observe(this, new Observer<List<Mentor>>() {
        @Override
        public void onChanged(@Nullable List<Mentor> mentorList) {
            if (mentorList != null) {
                for (Mentor m : mentorList) {
                    mentorNameList.add(m.getMentor_name());
                    mentorListMentor.add(m);
                }
                lookForMentor();
            }
        }
    });
    
    private void lookForMentor() {
       for(Mentor m: mentorListMentor){
        if (m.getMentor_id()==mentorId){
            String test = m.getMentor_name();
            int spinnerSelectionM2 = getIndexM(sp_CourseMentor, test);
            sp_CourseMentor.setSelection(spinnerSelectionM2);
        }
      }
    }
    
  • Поместите в наблюдателя значение for, измените DAO для комнаты, чтобы вернуть List, и используйте LiveData на вашем собственная модель представления:

MentorViewModel. java:

MentorViewModel extends ViewModel {
   private MutableLiveData<List<Mentor>> _mentorsLiveData = new MutableLiveData<List<Mentor>>();
   public LiveData<List<Mentor>> mentorsLiveData = (LiveData) _mentorsLiveData;

 void getAllMentors(){
    //room db query
    _mentorsLiveData.postValue(mentorsList);
 }
}

EditActivity. java:

mentorsViewModel.getAllMentors();
mentorViewModel.mentorsLiveData.observe(this, new Observer<List<Mentor>>() {
        @Override
        public void onChanged(@Nullable List<Mentor> mentorList) {
              mentorsListMentor.addAll(mentorList);
              sp_CourseMentorAdapter.notifyDataSetChanged();
              for(Mentor m: mentorListMentor){
                 if (m.getMentor_id()==mentorId){
                   String test = m.getMentor_name();
                   int spinnerSelectionM2 = getIndexM(sp_CourseMentor, test);
                   sp_CourseMentor.setSelection(spinnerSelectionM2);
                }
             }
            }
        }
    });
...