很抱歉,如果这是一个令人困惑的问题。正在为大学课程创建应用程序,我在OnCreate方法中遇到了(似乎是)竞争情况。
TL; DR-有时我的微调器会填充,并且我可以从中获取索引。有时在尝试获取特定索引时尚未填充。详细信息和代码如下。
该应用是大学生的“课程安排器”。
我正在创建一个活动,该活动显示现有课程信息并允许您对其进行编辑。在该活动的OnCreate方法中,我为课程的“ Mentors”填充了一个微调器,并为课程所属的“ Term”填充了一个微调器。此信息是从Room DB中提取的。
我针对一门新课程和一门课程进行单独的活动。对于“新课程”活动,一切正常。我成功getAllMentors()或getAllTerms()并填写了微调框。
对于“编辑课程”活动,还涉及一个额外的步骤,这似乎给我带来了一些问题。
[编辑课程时,我通过所有必要的EXTRAS传递了来自发起活动的意图。这是成功的。在OnCreate for EditCourseActivity中,我执行以下操作:
- 我从原始Activity传入的EXTRA中获取mentorID。
- 我访问我的MentorViewModel并调用我的getAllMentors()方法,该方法返回db中所有指导者的LiveData>。
- 因为它返回LiveData,所以我使用观察者并遍历LiveData,将每个指导者的姓名添加到列表中,然后整个导师名单。
- 我使用完整的指导者姓名列表中的信息填充微调器。
- 然后,我进行一个for循环,遍历List,查找与我在步骤1中从EXTRA抓取的ID相同的ID。
- 如果在该列表中找到匹配项,则调用getMentorName()方法以将其名称作为字符串获取。
- 我有一个methond getIndex(spinner,string),它将遍历提供的微调器,试图找到与以下内容匹配的字符串我抓取的传入(指导者姓名)应与ID匹配分配给课程的导师。此方法返回索引位置微调器中匹配的字符串的大小。
- 我将微调器选择设置为找到的索引。
我的任期基本相同。
我是一名新开发人员,我不习惯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循环?
或者是更好的方法来解决这个问题?
谢谢。
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);
}
}
}
}
});