Я использую «Фрагмент» для получения макета с двумя «фрагментами», поэтому мой класс расширяет «Фрагмент».
Я загружаю «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));
.
Если я прокомментирую приведенную выше строку, поскольку я сохраняю состояние до поворота экрана, после поворота экрана мои данные восстанавливаются, и все работает, как ожидалось, ЗА ИСКЛЮЧЕНИЕМ счетчика, который горит светлым цветом, таким образом быть плохо видимым.
Я понимаю, что могу создать свой собственный макет прядильщика и решить эту проблему, но я хотел бы знать, как я могу это решить.
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
для прядильщика.
nullpointerexception
. Вы решили эту проблему, используя специальный счетчик или что-то еще?
Похожие вопросы
Связанные вопросы
Новые вопросы
android
Android - это мобильная операционная система Google, используемая для программирования или разработки цифровых устройств (смартфоны, планшеты, автомобили, телевизоры, одежда, стекло, IoT). Для тем, связанных с Android, используйте специальные теги Android, такие как android-intent, android-activity, android-адаптер и т. Д. Для вопросов, не связанных с разработкой или программированием, но связанных с платформой Android, используйте эту ссылку: https: // android.stackexchange.com .
loadSpinner
?onCreateView
я делаю этоspinner = (Spinner) itemDataLayout.findViewById(R.id.availableValues); spinner.setOnItemSelectedListener(this);
, и вертушка загружается, представьте, изfunctionX
. Когда я нажимаю на элемент слеваlistview
, вызывается функцияfunctionX
. Если я прихожу изsavedrestoredstate
,functionX
вызывается изonStart()
onItemSelected
до того, как был вызванloadSpinner
, который устанавливает адаптер. Вы можете проверить порядок, установив точки останова вonItemSelected
и в строкеspinner.setAdapter()
и посмотреть, что вызывается первым после ротацииonItemSelected
, потому что счетчик еще не имеет дочерних элементов. Итак, у вас будет два варианта исправить это, но сначала вам нужно проверить, так ли это.loadSpinner
идет первым