Жизненный цикл Android Fragment над изменениями ориентации
Использование пакета совместимости для установки 2.2 с помощью фрагментов.
После перекодировки активности для использования фрагментов в приложении я не смог получить изменения ориентации/управления состоянием, поэтому я создал небольшое тестовое приложение с одним FragmentActivity и одним фрагментом.
Журналы изменений ориентации странны, с несколькими вызовами фрагментов OnCreateView.
Я, очевидно, что-то пропустил - как бы отделял фрагмент и снова привязывал его, а не создавал новый экземпляр, но я не вижу никакой документации, которая указывала бы, где я ошибаюсь.
Может кто-нибудь пролить свет на то, что я делаю неправильно здесь, пожалуйста.
Благодаря
После изменения ориентации журнал выглядит следующим образом.
Initial creation
12-04 11:57:15.808: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:57:15.945: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:16.081: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null
Orientation Change 1
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:57:39.031: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:39.167: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null
Orientation Change 2
12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:58:32.361: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null
Основная активность (FragmentActivity)
public class FragmentTestActivity extends FragmentActivity {
/** Called when the activity is first created. */
private static final String TAG = "FragmentTest.FragmentTestActivity";
FragmentManager mFragmentManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(TAG, "onCreate");
mFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
FragmentOne fragment = new FragmentOne();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}
И фрагмент
public class FragmentOne extends Fragment {
private static final String TAG = "FragmentTest.FragmentOne";
EditText mEditText;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "OnCreateView");
View v = inflater.inflate(R.layout.fragmentonelayout, container, false);
// Retrieve the text editor, and restore the last saved state if needed.
mEditText = (EditText)v.findViewById(R.id.editText1);
if (savedInstanceState != null) {
Log.d(TAG, "OnCreateView->SavedInstanceState not null");
mEditText.setText(savedInstanceState.getCharSequence("text"));
}
else {
Log.d(TAG,"OnCreateView->SavedInstanceState null");
}
return v;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, "FragmentOne.onSaveInstanceState");
// Remember the current text, to restore if we later restart.
outState.putCharSequence("text", mEditText.getText());
}
манифеста
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".activities.FragmentTestActivity"
android:configChanges="orientation">
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Ответы
Ответ 1
Вы размещаете свои фрагменты один поверх другого.
При изменении конфигурации старый фрагмент добавляет себя к новому действию при его воссоздании. Это большая боль в задней части большей части времени.
Вы можете остановить ошибки, возникающие с использованием того же фрагмента, а не воссоздать новый. Просто добавьте этот код:
if (savedInstanceState == null) {
// only create fragment if activity is started for the first time
mFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
FragmentOne fragment = new FragmentOne();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
} else {
// do nothing - fragment is recreated automatically
}
Будем предупреждены: проблемы будут возникать, если вы попытаетесь получить доступ к представлениям активности внутри фрагмента, поскольку жизненные циклы будут тонко изменяться. (Получение представлений из родительской активности из фрагмента непросто).
Ответ 2
Чтобы привести эту книгу," для обеспечения
постоянный пользовательский интерфейс, Android сохраняет макет фрагмента и связанный задний стек, когда
Активность перезапускается из-за изменения конфигурации. "(Стр. 124)
И способ приблизиться к тому, чтобы сначала проверить, уже ли заполнен стек фрагмента фрагмента, и создать экземпляр нового фрагмента, только если он не имеет значения:
@Override
public void onCreate(Bundle savedInstanceState) {
...
FragmentOne fragment = (FragmentOne) mFragmentManager.findFragmentById(R.id.fragment_container);
if (fragment == null) {
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container, new FragmentOne());
fragmentTransaction.commit();
}
}
Ответ 3
Метод onCreate() вашей активности вызывается после изменения ориентации, как вы видели. Таким образом, не выполняйте FragmentTransaction, которое добавляет фрагмент после изменения ориентации в вашей активности.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState==null) {
//do your stuff
}
}
Фрагменты должны и должны быть неизменными.
Ответ 4
Вы можете @Override
FragmentActivity с помощью onSaveInstanceState()
. Обязательно не вызывайте super.onSaveInstanceState()
в методе.
Ответ 5
Мы всегда должны стараться исключить исключение nullpointer, поэтому сначала нужно проверить метод saveinstance для информации о связке. для краткого объяснения, чтобы проверить этот блог ссылка
public static class DetailsActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
// If the screen is now in landscape mode, we can show the
// dialog in-line with the list so we don't need this activity.
finish();
return;
}
if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
}
}
}
Ответ 6
Если вы просто выполняете проект, менеджер проекта говорит, что вам нужно выполнить экран переключения функций, но вы не хотите, чтобы экран переключил нагрузку на другой макет (можно создать макет и систему макета порта.
Вы автоматически определяете состояние экрана, загружаете соответствующий макет), из-за необходимости повторной инициализации активности или фрагмента, пользовательский интерфейс не является хорошим, а не непосредственно на экране, я ссылаюсь на
? URL = YgNfP-VHY-Nuldi7YHTfNet3AtLdN-w__O3z1wLOnzr3wDjYo7X7PYdNyhw8R24ZE22xiKnydni7R0r35s2fOLcHOiLGYT9Qh_fjqtytJki & = & WD амп; eqid = f258719e0001f24000000004585a1082
Предпосылка заключается в том, что ваш макет, используя вес способа макета макета, выглядит следующим образом:
<LinearLayout
Android:id= "@+id/toplayout"
Android:layout_width= "match_parent"
Android:layout_height= "match_parent"
Android:layout_weight= "2"
Android:orientation= "horizontal" >
Итак, мой подход - при переключении экрана не нужно загружать новый макет файла вида, изменять макет в динамических весах onConfigurationChanged, следующие шаги:
1 первый набор: AndroidManifest.xml в атрибуте активности: android: configChanges = "keyboardHidden | orientation | screenSize"
Чтобы предотвратить переключение экрана, избегайте повторной загрузки, чтобы иметь возможность отслеживать в onConfigurationChanged
2 перезапишите активность или фрагмент в методе onConfigurationChanged.
@Override
Public void onConfigurationChanged (Configuration newConfig) {
Super.onConfigurationChanged (newConfig);
SetContentView (R.layout.activity_main);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
//On the layout / / weight adjustment
LinearLayout toplayout = (LinearLayout) findViewById (R.id.toplayout);
LinearLayout.LayoutParams LP = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.0f);
Toplayout.setLayoutParams (LP);
LinearLayout tradespace_layout = (LinearLayout) findViewById(R.id.tradespace_layout);
LinearLayout.LayoutParams LP3 = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.8f);
Tradespace_layout.setLayoutParams (LP3);
}
else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
{
//On the layout / / weight adjustment
LinearLayout toplayout = (LinearLayout) findViewById (R.id.toplayout);
LinearLayout.LayoutParams LP = new LayoutParams (LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.8f);
Toplayout.setLayoutParams (LP);
LinearLayout tradespace_layout = (LinearLayout) findViewById (R.id.tradespace_layout);
LinearLayout.LayoutParams LP3 = new LayoutParams (LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.0f);
Tradespace_layout.setLayoutParams (LP3);
}
}
Ответ 7
При изменении конфигурации инфраструктура создаст для вас новый экземпляр фрагмента и добавит его в действие. Поэтому вместо этого:
FragmentOne fragment = new FragmentOne();
fragmentTransaction.add(R.id.fragment_container, fragment);
сделайте следующее:
if (mFragmentManager.findFragmentByTag(FRAG1_TAG) == null) {
FragmentOne fragment = new FragmentOne();
fragmentTransaction.add(R.id.fragment_container, fragment, FRAG1_TAG);
}
Обратите внимание, что структура добавляет новый экземпляр FragmentOne в изменение ориентации, если вы не вызываете setRetainInstance (true), и в этом случае он добавит старый экземпляр FragmentOne.