我们在Lollipop遇到了一些非常奇怪的事情。
我们有一个搜索屏幕,一个列表屏幕,然后是一个详细信息屏幕。
执行搜索后,将显示列表。然后,用户可以选择一个条目并获得更多详细信息。 在KK以上的Android版本上,一切都很棒。
然而,在Lollipop从列表屏幕退出到搜索屏幕时,我们有时会崩溃。 这发生在列表适配器的getCount()中 - 它试图访问我们设置为null的项。
我不明白为什么在退出活动后更新列表视图。 为了检查操作的顺序,我注册了一个ActivityLifecycleCallbacks并打印出每个条目的条目。
我看到以下内容(从详细信息屏幕开始 - >列表屏幕 - >搜索屏幕。
onActivityPaused com.applicat.meuchedet.DoctorSearchScreen@43db605
onActivityCreated com.applicat.meuchedet.DoctorListScreen@108d4747
onActivityStarted com.applicat.meuchedet.DoctorListScreen@108d4747
onActivityResumed com.applicat.meuchedet.DoctorListScreen@108d4747
onActivityStopped com.applicat.meuchedet.DoctorSearchScreen@43db605
onActivityPaused com.applicat.meuchedet.DoctorListScreen@108d4747
onActivityCreated com.applicat.meuchedet.DoctorSwipeableDetailsScreen@35b3ff59
onActivityStarted com.applicat.meuchedet.DoctorSwipeableDetailsScreen@35b3ff59
onActivityResumed com.applicat.meuchedet.DoctorSwipeableDetailsScreen@35b3ff59
onActivityStopped com.applicat.meuchedet.DoctorListScreen@108d4747
onActivityPaused com.applicat.meuchedet.DoctorSwipeableDetailsScreen@35b3ff59
onActivityStarted com.applicat.meuchedet.DoctorListScreen@108d4747
onActivityResumed com.applicat.meuchedet.DoctorListScreen@108d4747
onActivityStopped com.applicat.meuchedet.DoctorSwipeableDetailsScreen@35b3ff59
onActivityDestroyed com.applicat.meuchedet.DoctorSwipeableDetailsScreen@35b3ff59
onActivityPaused com.applicat.meuchedet.DoctorListScreen@108d4747
onActivityStarted com.applicat.meuchedet.DoctorSearchScreen@43db605
onActivityResumed com.applicat.meuchedet.DoctorSearchScreen@43db605
可以看出,当从详细信息活动转到列表活动时,一切正常 - 它会暂停详细信息活动,然后恢复列表活动,最后停止并销毁详细信息活动。
但是,当从列表移动到搜索时,它不会到达列表活动的停止和销毁。 搜索活动将恢复并显示,然后由于列表活动尝试更新适配器中的内容而导致应用程序崩溃。 更奇怪的是,即使在棒棒糖上也不会发生这种情况。
将适配器连接到列表视图:
this._adapter = new ArrayAdapter<ViewGroup>(this, android.R.layout.simple_expandable_list_item_1) {
// We want to force at least NUM_OF_ITEMS_DISPLAYED rows on the screen. So, we set getCount to return NUM_OF_ITEMS_DISPLAYED
// if there are less than NUM_OF_ITEMS_DISPLAYED rows.
// getView then chooses the required view for the row depending on whether it is a row with data or an empty one.
@Override
public int getCount() {
return Math.max(ListScreen.this._maxNumOfItemsToDisplay, ListScreen.this.getActualNumOfItemsInList());
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Update the number of items that are visible as this screen is displayed:
ListScreen.this._numOfItemsDisplayedOnStart = Math.max(ListScreen.this._numOfItemsDisplayedOnStart, position);
// Choose the view to use depending on the type of row to be displayed
// The input convertview, if it is not null, will always be the one that matches the type given.
// This is due to the code in getItemViewType returning the type of view required for this row.
int viewType = getItemViewType(position);
boolean isEnabled = itemIsClickable(position);
switch (viewType){
case ROW_WITH_DATA: // Normal data view
convertView = ListScreen.this.getConvertView(convertView, parent, viewType, position);
_viewHolder.position = position;
MeuchedetApplication.setBackgroundDrawable(convertView, getResources().getDrawable(isEnabled ? ListScreen.this.getClickableItemBackground() :
ListScreen.this.getNonClickableItemBackground()));
setRecordData(position, (ViewGroup) convertView, _viewHolder);
_viewHolder.setClickable(itemIsClickable(position));
break;
case ROW_WITHOUT_DATA: // Empty row
if (convertView == null) {
convertView = (ViewGroup) li.inflate(ListScreen.this.getEmptyItemLayout(), parent, false);
}
ListScreen.this.makeInvisible(convertView);
break;
}
if (itemIsClickable(position)) {
convertView.setClickable(false);
convertView.setFocusable(false);
} else {
convertView.setClickable(true);
convertView.setFocusable(true);
}
return convertView;
}
// This method indicates that we have two different view layouts with the ListView.
// In our case, one if for the normal row and one is for the empty row
@Override
public int getViewTypeCount() {
return 2;
}
// This method returns which type of view to use for which row.
// We will use the normal type for the original rows and the empty type for any overflow rows.
// So, type 0 = normal, type 1 = empty
//
// This method is called automatically by ListView to determine what type of view to fetch from the recycler.
// It is then called in our getView code to determine what type of view we have or should create.
@Override
public int getItemViewType(int position) {
return (position < ListScreen.this._results._resultsList.size()) ? ROW_WITH_DATA : ROW_WITHOUT_DATA;
}
};
_lv.setAdapter(this._adapter);
&#34; getConvertView&#34;是一个获取此行的填充视图的方法。在扩展此方法的类中重写此方法。