旋转屏幕后找不到微调器

时间:2013-12-29 22:07:16

标签: android android-layout listview android-fragments

我正在使用'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 启用的微调器浅色,因此看不清楚。

我知道我可以创建自己的'微调'布局并解决这个问题,但我想知道如何解决这个问题。

1 个答案:

答案 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 */ }

这会阻止设置mDataChangedonMeasure不会触发fireOnSelected

额外注意

在绝对不建议覆盖super. / onSavedInstanceState时,不会调用活动onRestoreInstanceState实施,因为至少您无法自动保存内部视图的状态(包括您的微调器) )。
我鼓励您只做这个来验证上面解释的行为并看到NPE已经消失。

首选解决方案是为.xml布局中的微调器项目定义具有所需颜色的TextView,并将其用于为微调器构建ArrayAdapter