旋转屏幕后找不到微调器

Fav*_*las 5 android listview android-layout android-fragments

我正在使用'Fragment'来获得一个带有两个'片段'的布局,所以我的课程扩展了'Fragment'.

我在左侧'片段'上加载'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
}
Run Code Online (Sandbox Code Playgroud)

上面的代码按预期工作UNTIL我旋转设备的屏幕.在这里,我得到一个nullpointerexception((TextView) parent.getChildAt(0)).setTextColor(getResources().getColor(R.color.black));.

如果我评论上面这一行,因为我在旋转屏幕之前保存状态,在旋转屏幕后,我的数据将被恢复并且所有工作都按预期工作除了浅色的微调器因此不可见.

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

kir*_*wka 9

屏幕旋转后,您的Spinner视图尚未附加子视图(您可以通过调用验证它parent.getChildCount()),因此parent.getChildAt(0)返回null,从而导致NPE.

说明

创建活动后,Android版会显示通过调用其内容onMeasure(),然后onLayout()在布局层次中的每个视图.

Spinner将创建其子视图,使用适配器中的数据填充,并在调用期间附加onLayout(),如您在此处所见.

因此,通常对于您的Spinner,您将有序列:onMeasure- > onLayout- > onItemSelected
并且onLayout之前被调用onItemSelected- 在初始活动启动期间,一切正常.

现在,让我们来看看旋转屏幕时会发生什么:

活动被破坏之前其onSavedInstanceState被称为其传播调用SpinneronSavedInstanceState,将保存当前选定的位置.

轮换后,将重新创建您的活动,然后onRestoreInstanceState调用它.

onRestoreInstanceState调用Activity#时,它最终会调用Spinner的onRestoreInstanceState,它具有以下代码:

    SavedState ss = (SavedState) state;
    //...some code
    if (ss.selectedId >= 0) {
        mDataChanged = true;
        //...some more code
    }
Run Code Online (Sandbox Code Playgroud)

如您所见,如果使用onSavedInstanceState保存微调器的先前状态,它将始终设置mDataChanged标志.

然后,调用onMeasure(),它具有以下代码:

    if (mDataChanged) {
        handleDataChanged();
    }
Run Code Online (Sandbox Code Playgroud)

handleDataChanged()的实现最终将调用fireOnSelected(),触发Spinner的onItemSelected.

因此onItemSelectedonMeasure之前被调用onLayout.
如上所述,SpinneronLayout召唤之前没有孩子.

希望现在问题很清楚.

解决方法

要确认该行为并解决NPE,您只需在活动中为onSavedInstanceState/ 提供空实现onRestoreInstanceState(无需调用超级实现):

@Override 
protected void onSaveInstanceState(Bundle outState) { /* do nothing */ }
Run Code Online (Sandbox Code Playgroud)

这样可以防止设置mDataChanged,onMeasure也不会触发fireOnSelected.

额外的说明

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

最好的解决方案是为TextView.xml布局中的微调器项目定义所需的颜色,并使用它来构造ArrayAdapter微调器.