Зачем мне когда-либо хотеть `setRetainInstance (false)`? - Или - Правильный способ обработки вращения устройства
Пожалуйста, поправьте меня, если я ошибаюсь в этом. Это своего рода уточняющий вопрос, поскольку я не видел его явно написанным где-либо.
В Android 4 вы можете вызвать setRetainInstance(true)
на Fragment
, чтобы при изменении конфигурации (что в основном означает вращение устройства), java-объект Fragment
не был уничтожен, а новый экземпляр его не был создано. То есть экземпляр сохраняется.
Это гораздо более разумно и менее бесит, чем в Android 1-3, поскольку вам не нужно иметь дело с onRetainNonConfiguration
State
Instance()
и собирать все ваши данные, чтобы он может быть передан в новый экземпляр Fragment
(или Activity
) только для повторного разделения. Это в основном то, что вы ожидали бы, и, возможно, как он должен был работать с Activity
с самого начала.
С setRetainInstance(true)
вид также воссоздается (onCreateView()
вызывается) при вращении, как вы ожидали. И я предполагаю (не проверено), что разрешение ресурсов (layout
vs layout-land
) работает.
Итак, мой вопрос в два раза:
- Почему это было не так с
Activities
с самого начала.
- Почему это не по умолчанию? Есть ли какая-либо причина, по которой вы действительно хотите, чтобы ваш
Fragment
был бесцельно уничтожен и воссоздан при ротации? Потому что я не могу придумать.
Изменить
Чтобы выяснить, как я это сделаю:
class MyFragment extends Fragment
{
// All the data.
String mDataToDisplay;
// etc.
// All the views.
TextView mViewToDisplayItIn;
// etc.
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setRetainInstance(true);
mDataToDisplay = readFromSomeFileOrWhatever(); // Ignoring threading issues for now.
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.my_fragment, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
// At this point if mViewToDisplayItIn was not null, the old one will be GC'd.
mViewToDisplayItIn = view.findViewById(R.id.the_text_view);
mViewToDisplayItIn.setText(mDataToDisplay);
}
// Optionally:
@Override
public void onDestroyView()
{
// All the view (and activity) to be GC'd.
mViewToDisplayItIn = null;
}
}
Ответы
Ответ 1
так что при изменении конфигурации (что в основном означает вращение устройства)
И изменение языка, изменение SIM-карты, изменение размера шрифта по умолчанию, подключение или удаление внешней клавиатуры, установка устройства на док-станцию или удаление его с того же самого и т.д.
вам не нужно иметь дело с onRetainNonConfigurationState()
Это onRetainNonConfigurationInstance()
.
объединить все ваши данные, чтобы он мог быть передан в новый экземпляр Fragment (или Activity) только для повторного разделения.
Ваши данные уже должны быть "связаны" (например, экземпляр частного статического внутреннего класса), и поэтому его не нужно "связывать" или "разделять". Кроме того, часто это не должно быть "все ваши данные", если вы не являетесь поклонником утечек памяти.
И я предполагаю (не проверено), что разрешение ресурса (компоновка и макет-земля) работает.
Правильно.
Есть ли какая-либо причина, по которой вы действительно хотите, чтобы ваш фрагмент был бесцельно уничтожен и воссоздан при вращении?
Конечно.
Как вы заметили, все виджеты воссозданы, поэтому данные, привязанные к виджетам, не только не нужны для сохранения. Если вы специально не reset те, что были в null
на сохраненном фрагменте, до тех пор, пока onCreateView()
не будет вызван снова, эти члены данных будут помещаться в старые виджеты, которые будут удерживать старый экземпляр активности, что предотвратит эту старую активность например, от сбора мусора. AFAIK, onCreateView()
не будет вызываться до тех пор, пока фрагмент не будет повторно отображаться, что может не быть достаточно долго (фрагмент не используется в новой ориентации, или фрагмент для некоторой страницы в ViewPager
, что пользователь посетил в старой ориентации, но не пересматривает новую ориентацию и т.д.). Это означает, что сохраненный фрагмент может содержать старый объект активности в течение значительного периода времени. В зависимости от того, что еще может занимать эта деятельность (например, большие объекты Bitmap
), это может быть плохо.
Аналогично, фрагмент, который сам содержит большие данные, где этот фрагмент может использоваться или не может использоваться после изменения конфигурации, является тем, который не следует сохранять.
Кроме того, будут фрагменты, которые просто не нужно ничего сохранять (например, все данные заполняются Loaders
, которые уже знают об изменениях конфигурации и обрабатывают их соответственно).
И так далее.
По умолчанию фрагменты, которые не сохраняются, являются самым безопасным способом действий в отношении проблем сбора мусора. Вы можете выбрать, чтобы некоторые фрагменты были сохранены, но тогда на вас лежит ответственность, чтобы убедиться, что вы не приворачиваете себя, делая это.
Ответ 2
Я не знаю ответа на первый вопрос. С самого начала это должно было быть так. Думаю, кто-то в Google подумал, что они действительно умны, придумывая эту схему.
Второй вопрос, однако, намного проще. Это не по умолчанию, потому что это не то, что разработали Android. Android развивает знание, что экземпляр умирает при вращении и ожидает его. Изменение значения по умолчанию привело бы к тому, что многие разработчики действительно разозлились.