Я использую «Фрагмент» для получения макета с двумя «фрагментами», поэтому мой класс расширяет «Фрагмент».

Я загружаю «ListView» слева «фрагмент» и справа «фрагмент». У меня есть еще один измененный «ListView». Здесь у меня есть «Спиннер», и мне нужно изменить его цвет.

У меня есть такой код:

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
}

Приведенный выше код работает должным образом ДО я поверну экран своего устройства. Вот, я получаю nullpointerexception в ((TextView) parent.getChildAt(0)).setTextColor(getResources().getColor(R.color.black));.

Если я прокомментирую приведенную выше строку, поскольку я сохраняю состояние до поворота экрана, после поворота экрана мои данные восстанавливаются, и все работает, как ожидалось, ЗА ИСКЛЮЧЕНИЕМ счетчика, который горит светлым цветом, таким образом быть плохо видимым.

Я понимаю, что могу создать свой собственный макет прядильщика и решить эту проблему, но я хотел бы знать, как я могу это решить.

5
Favolas 30 Дек 2013 в 02:07
Откуда вы звоните loadSpinner?
 – 
Szymon
30 Дек 2013 в 02:21
Привет. В onCreateView я делаю это spinner = (Spinner) itemDataLayout.findViewById(R.id.availableValues); spinner.setOnItemSelectedListener(this);, и вертушка загружается, представьте, из functionX. Когда я нажимаю на элемент слева listview, вызывается функция functionX. Если я прихожу из savedrestoredstate, functionX вызывается из onStart()
 – 
Favolas
30 Дек 2013 в 02:30
1
У вас, вероятно, был запущен onItemSelected до того, как был вызван loadSpinner, который устанавливает адаптер. Вы можете проверить порядок, установив точки останова в onItemSelected и в строке spinner.setAdapter() и посмотреть, что вызывается первым после ротации
 – 
kiruwka
30 Дек 2013 в 02:36
Если то, что я написал в предыдущем комментарии, соответствует действительности, у вас всегда будет NPE в onItemSelected, потому что счетчик еще не имеет дочерних элементов. Итак, у вас будет два варианта исправить это, но сначала вам нужно проверить, так ли это.
 – 
kiruwka
30 Дек 2013 в 02:44
Нет. loadSpinner идет первым
 – 
Favolas
30 Дек 2013 в 02:44

1 ответ

Лучший ответ

После поворота экрана к вашему представлению Spinner еще не прикреплены дочерние представления (вы можете проверить это, вызвав parent.getChildCount()), поэтому ваш parent.getChildAt(0) возвращает значение null, что приводит к NPE.

Пояснения

После создания действия Android отображает его содержимое, вызывая onMeasure(), за которым следует onLayout() для каждого представления в иерархии макета.

Spinner будет иметь дочерние представления, созданные, заполненные данными из адаптера и прикрепленные во время вызова к onLayout(), как вы можете см. здесь.

Итак, обычно для вашего Spinner у вас будет последовательность: onMeasure -> onLayout -> onItemSelected
а так как onLayout вызывается перед onItemSelected - у вас все работает нормально во время первоначального запуска активности.

Теперь давайте посмотрим, что происходит при повороте экрана:

Перед уничтожением Activity вызывается его onSavedInstanceState, который распространяет вызов на onSavedInstanceState Spinner, который сохранит текущую выбранную позицию.

После ротации ваше действие создается заново, а затем вызывается его onRestoreInstanceState.

Когда вызывается действие № onRestoreInstanceState, оно в конечном итоге вызывает onRestoreInstanceState, содержащий следующий код:

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

Как видите, он всегда будет устанавливать флаг mDataChanged, если предыдущее состояние счетчика было сохранено с помощью onSavedInstanceState.

Затем onMeasure (), имеющий следующий фрагмент кода:

    if (mDataChanged) {
        handleDataChanged();
    }

Реализация handleDataChanged () в конечном итоге вызовет fireOnSelected (), запускающий onItemSelected Spinner.

Таким образом, onItemSelected вызывается во время onMeasure, до onLayout.
И, как объяснялось выше, Spinner не имеет потомков до вызова onLayout.

Надеюсь, проблема теперь ясна.

Обходной путь

Чтобы подтвердить это поведение и разрешить NPE, вы можете просто предоставить пустую реализацию для onSavedInstanceState / onRestoreInstanceState в своей деятельности (без вызова супер-реализации):

@Override 
protected void onSaveInstanceState(Bundle outState) { /* do nothing */ }

Это предотвратит настройку mDataChanged и onMeasure не вызовет fireOnSelected.

Дополнительное примечание

Не вызывать реализацию Activity super. при переопределении onSavedInstanceState / onRestoreInstanceState определенно не рекомендуется, поскольку как минимум вы не сможете автоматически сохранять состояния ваших внутренних представлений (включая счетчик). < br /> Я призываю вас сделать это только для того, чтобы проверить поведение, описанное выше, и убедиться, что NPE исчез.

Предпочтительным решением является определение TextView с желаемым цветом для элемента прядильщика в макете .xml и использование его для создания ArrayAdapter для прядильщика.

9
kiruwka 2 Янв 2014 в 03:05
Большое спасибо за это объяснение. Ты прав. Собираюсь реализовать свой собственный спиннер.
 – 
Favolas
1 Янв 2014 в 16:51
Рад, что помог. Пожалуйста, рассмотрите возможность принятия. И с новым годом!
 – 
kiruwka
1 Янв 2014 в 18:00
Привет ... у меня такая же проблема ... я реализовал свой собственный счетчик ... все еще получаю тот же nullpointerexception. Вы решили эту проблему, используя специальный счетчик или что-то еще?
 – 
Sash_KP
26 Авг 2014 в 16:54
 – 
Sash_KP
26 Авг 2014 в 17:17
1
@Favolas, ваше решение определяло цвет в XML? У меня есть аналогичный вопрос, но я не могу полагаться на определение цвета в XML, потому что цвет известен только во время выполнения. Мой вопрос здесь: stackoverflow.com/questions/33747884/…
 – 
Rock Lee
17 Ноя 2015 в 09:49