我正在使用'Fragment'来获得一个带有两个'片段'的布局,所以我的课程扩展了'Fragment'。
我在左侧'片段'上加载'ListView',在右侧'片段'上加载'ListView',我有另一个修改过的'ListView'。在这里,我有一个'Spinner',我必须改变它的颜色。
我有这段代码:
private void loadSpinner(int value) {
//Not relevant code
adapter = new ArrayAdapter<CharSequence>(getActivity().getApplicationContext(), android.R.layout.simple_spinner_item, data);
adapter.setDropDownViewResource(R.layout.spinner);
spinner.setAdapter(adapter);
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String value = parent.getItemAtPosition(position).toString();
((TextView) parent.getChildAt(0)).setTextColor(getResources().getColor(R.color.black));
//Some code
}
上面的代码按预期工作 UNTIL 我旋转设备的屏幕。在这里,我在nullpointerexception
获得((TextView) parent.getChildAt(0)).setTextColor(getResources().getColor(R.color.black));
。
如果我对上述行进行评论,由于我在旋转屏幕之前保存状态,在旋转屏幕后,我的数据将被恢复,并且所有数据都按预期工作 EXCEPT 启用的微调器浅色,因此看不清楚。
我知道我可以创建自己的'微调'布局并解决这个问题,但我想知道如何解决这个问题。
答案 0 :(得分:9)
屏幕轮换后,您的Spinner
视图尚未附加子视图(您可以通过调用parent.getChildCount()
进行验证),因此parent.getChildAt(0)
返回null,从而生成{{1} }。
创建活动后,Android会为布局层次结构中的每个视图调用NPE
后跟onMeasure()
来显示其内容。
onLayout()
会创建子视图,使用适配器填充数据,并在调用Spinner
期间附加,see here。
因此,通常对于您的Spinner,您将拥有序列:onLayout()
- &gt; onMeasure
- &gt; onLayout
并且因为在onItemSelected
之前调用onLayout
- 在初始活动启动期间一切正常。
现在,让我们看看旋转屏幕时会发生什么:
在销毁活动之前,会调用onItemSelected
来调用onSavedInstanceState
传播Spinner
onSavedInstanceState
来保存当前所选位置。
轮换后,您的活动会重新创建,然后会调用onRestoreInstanceState
。
当调用Activity#onRestoreInstanceState
时,它最终将调用Spinner的onRestoreInstanceState,其中包含以下代码:
SavedState ss = (SavedState) state;
//...some code
if (ss.selectedId >= 0) {
mDataChanged = true;
//...some more code
}
如您所见,如果使用onSavedInstanceState保存微调器的先前状态,它将始终设置mDataChanged标志。
然后,调用onMeasure(),其中包含以下代码:
if (mDataChanged) {
handleDataChanged();
}
handleDataChanged()的实现最终会调用fireOnSelected(),触发Spinner的onItemSelected
。
因此在onItemSelected
onMeasure
之前调用onLayout
。{
如上所述,Spinner
在调用onLayout
之前没有孩子。
希望问题现在清楚。
要确认该行为并解决NPE,您只需在活动中为onSavedInstanceState
/ onRestoreInstanceState
提供空实现(无需调用超级实现):
@Override
protected void onSaveInstanceState(Bundle outState) { /* do nothing */ }
这会阻止设置mDataChanged
而onMeasure
不会触发fireOnSelected
。
在绝对不建议覆盖super.
/ onSavedInstanceState
时,不会调用活动onRestoreInstanceState
实施,因为至少您无法自动保存内部视图的状态(包括您的微调器) )。
我鼓励您只做这个来验证上面解释的行为并看到NPE
已经消失。
首选解决方案是为.xml布局中的微调器项目定义具有所需颜色的TextView
,并将其用于为微调器构建ArrayAdapter
。