Android Java - OnCreate 中的竞争条件与两个观察者并制作列表

Android Java - Race Condition in OnCreate with two Observers and making lists

抱歉,如果这是一个令人费解的问题。正在为大学课程创建应用程序,我 运行 在我的 OnCreate 方法中陷入(似乎是)竞争条件。

TL;DR - 有时我的微调器会填充,我可以从中获取索引。有时在尝试获取特定索引时尚未填充。详细信息和代码如下。

该应用程序是 "course scheduler" 面向大学生的应用程序。

我正在创建一个 Activity 来显示现有课程信息并允许您对其进行编辑。在此 Activity 的 OnCreate 方法中,我正在为课程填充 "Mentors" 的微调器和课程所属的 "Term" 微调器。此信息是从 Room DB 中提取的.

我有一个单独的 activity 用于新课程和编辑课程。对于 "new course" activity,一切正常。我 getAllMentors() 或 getAllTerms() 成功并填充微调器列表。

对于 "Edit Course" Activity,有一个额外的步骤,它似乎给我带来了一些问题。

在编辑课程时,我会传递原始 Activity 的意图以及所有必要的 EXTRAS。这是成功的。 在 EditCourseActivity 的 OnCreate 中,我执行以下操作:

  1. I get the mentorID from the EXTRA that's passed in from the originating Activity.
  2. I access my MentorViewModel and call my getAllMentors() method which returns LiveData> of all mentors in the db.
  3. because it returns LiveData, I use an observer and loop through the LiveData adding the Name of each mentor to a List and the entire mentor to a List.
  4. I populate my spinner with the information in List full of mentor names.
  5. then I do a for loop, looping through List looking for one that has the same id as what I grabbed form the EXTRA in step 1.
  6. If I find a match in that list, I call a getMentorName() method to snag their name as a string.
  7. I have a methond getIndex(spinner, string) that will loop through the provided spinner, trying to find a match for the string that's passed in (mentors name) that I grabbed that should match the ID of the mentor assigned to the course. This method returns index location of the matched string in the spinner.
  8. I set the spinner selection to the index found.

我对学期进行基本相同的处理。

我是一名新开发人员,我不习惯 OnCreate 运行同步代码。 因此,我似乎在填充微调器的导师姓名列表和调用我的 getIndex() 方法之间存在竞争条件。
有时微调器被填充并且 getIndex 正常工作并设置正确的指导者。有时微调器是空的,而我的 getIndex() returns -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() 并填充微调器,然后有 for 循环 运行?

或者更好的处理方式?

提前致谢。

Room 总是 运行 将代码放在单独的线程上,而不是 Main/UI 线程上。您可以使用

更改该行为

allowMainThreadQueries()

初始化数据库后。这将首先使查询 运行,填充您的列表,然后 运行 您的 for 循环代码。我不推荐这种方法,因为在 UI 线程上进行查询是一种不好的做法。

您有两个选择:

  • 将您的 foor 循环更改为一个函数,并在添加来自观察者的值后调用它:

    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 放在观察者中,将 Room DAO 更改为 return 列表并在您自己的视图模型上使用 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);
                }
             }
            }
        }
    });