Android片段生命周期的方向变化

使用兼容性包使用Fragments来定位2.2。

重新编码一个活动在应用程序中使用片段后,我无法获得方向更改/状态pipe理工作,所以我创build了一个小的testing应用程序与一个单一的FragmentActivity和一个单一的片段。

来自方向更改的日志很奇怪,多个调用片段OnCreateView。

我很明显错过了一些东西 – 比如去分割片段并重新连接它,而不是创build一个新的实例,但是我看不到任何能够指明我要出错的文档。

任何人都可以阐明我在这里做错了什么请。 谢谢

方向更改后,日志如下所示。

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()); } 

performance

 <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> 

你正在把你的片段分层叠叠在一起。

当发生configuration更改时,旧的Fragment会在重新创build时将自己添加到新的Activity中。 大部分时间这是一个巨大的痛苦。

您可以停止使用相同片段发生的错误,而不是重新创build新的错误。 只需添加以下代码:

 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 } 

不过要注意:如果你尝试从Fragment中访问活动视图,将会发生问题,因为生命周期会发生微妙的变化。 (从片段的父级活动获取视图并不容易)。

为了引用这本书 ,“为了确保一致的用户体验,当由于configuration改变而重新启动活动时,Android会保留片段布局和关联的堆栈”。 (第124页)

解决这个问题的方法是首先检查Fragment返回堆栈是否已经被填充,并且只有在没有:

 @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(); } } 

您的活动的onCreate()方法在方向更改后调用,如您所见。 所以,不要执行FragmentTransaction,在活动中改变方向后添加Fragment。

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState==null) { //do your stuff } } 

碎片应该而且必须保持不变。

你可以@Override使用onSaveInstanceState() @Override FragmentActivity。 请确保不要在方法中调用super.onSaveInstanceState()

我们应该总是尝试防止空指针exception,所以我们必须首先检查bundleinstance的方法。 作简要的解释来检查这个博客链接

 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(); } } } 

如果你只是做一个项目,那么项目经理说你需要实现切换function画面,但是你不想切换加载不同的布局(可以创build布局和布局 – 端口系统。

你会自动判断屏幕状态,加载相应的布局),因为需要重新初始化activity或fragment,用户体验不好,不能直接在屏幕上切换,我是指? URL = YgNfP-VHY-Nuldi7YHTfNet3AtLdN-w__O3z1wLOnzr3wDjYo7X7PYdNyhw8R24ZE22xiKnydni7R0r35s2fOLcHOiLGYT9Qh_fjqtytJki&WD =&eqid = f258719e0001f24000000004585a1082

前提是你的布局使用layout_weight布局方式的权重,方法如下:

 <LinearLayout Android:id= "@+id/toplayout" Android:layout_width= "match_parent" Android:layout_height= "match_parent" Android:layout_weight= "2" Android:orientation= "horizontal" > 

所以我的做法是,在屏幕切换时,不需要加载视图文件的新布局,在onConfigurationChangeddynamic权重中修改布局,步骤如下:1.首先设置:androidManifest.xml中的activity属性:android:configChanges =“keyboardHidden | orientation | screenSize”为了防止屏幕切换,避免重新加载,以便能够在onConfigurationChanged方法中监视onConfigurationChanged 2重写活动或片段。

 @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); } } 

在configuration更改时,框架将为您创build片段的新实例并将其添加到活动中。 所以,而不是这个:

 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); } 

请注意,除非您调用setRetainInstance(true),否则框架会在方向更改上添加一个新的FragmentOne实例,在这种情况下,它将添加旧的FragmentOne实例。