Android Java-OnCreate中的竞争条件,带有两个观察者并列出列表

问题描述 投票:0回答:1

很抱歉,如果这是一个令人困惑的问题。正在为大学课程创建应用程序,我在OnCreate方法中遇到了(似乎是)竞争情况。

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

该应用是大学生的“课程安排器”。

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

我针对一门新课程和一门课程进行单独的活动。对于“新课程”活动,一切正常。我成功getAllMentors()或getAllTerms()并填写了微调框。

对于“编辑课程”活动,还涉及一个额外的步骤,这似乎给我带来了一些问题。

[编辑课程时,我通过所有必要的EXTRAS传递了来自发起活动的意图。这是成功的。在OnCreate for EditCourseActivity中,我执行以下操作:

  1. 我从原始Activity传入的EXTRA中获取mentorID。
  2. 我访问我的MentorViewModel并调用我的getAllMentors()方法,该方法返回db中所有指导者的LiveData>。
  3. 因为它返回LiveData,所以我使用观察者并遍历LiveData,将每个指导者的姓名添加到列表中,然后整个导师名单。
  4. 我使用完整的指导者姓名列表中的信息填充微调器。
  5. 然后,我进行一个for循环,遍历List,查找与我在步骤1中从EXTRA抓取的ID相同的ID。
  6. 如果在该列表中找到匹配项,则调用getMentorName()方法以将其名称作为字符串获取。
  7. 我有一个methond getIndex(spinner,string),它将遍历提供的微调器,试图找到与以下内容匹配的字符串我抓取的传入(指导者姓名)应与ID匹配分配给课程的导师。此方法返回索引位置微调器中匹配的字符串的大小。
  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()首先完成并填充微调器,然后运行for循环?

或者是更好的方法来解决这个问题?

谢谢。

java android spinner race-condition oncreate
1个回答
0
投票

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以返回列表,并在您自己的viewmodel上使用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);
                }
             }
            }
        }
    });
© www.soinside.com 2019 - 2024. All rights reserved.