Android Fragment生命周期超过方向更改

Mar*_*inS 115 android orientation android-fragments android-activity

使用兼容包以使用Fragments定位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
Run Code Online (Sandbox Code Playgroud)

主要活动(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();
}
Run Code Online (Sandbox Code Playgroud)

而片段

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());
}
Run Code Online (Sandbox Code Playgroud)

表现

<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>
Run Code Online (Sandbox Code Playgroud)

Gra*_*eme 184

你将你的碎片层叠在一起.

当配置发生更改时,旧的Fragment会在重新创建时将其自身添加到新的Activity中.这在大多数时候是后方的巨大痛苦.

您可以通过使用相同的片段来停止发生的错误,而不是重新创建新的片段.只需添加此代码:

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
}
Run Code Online (Sandbox Code Playgroud)

但请注意:如果您尝试从Fragment内部访问活动视图,则会出现问题,因为生命周期会微妙地改变.(从片段中获取父活动的视图并不容易).

  • "大多数时候这是后方的巨大痛苦"(竖起大拇指) (52认同)
  • 官方文件中是否有类似的断言?这不是指南中所说的矛盾:"当活动被破坏时,所有碎片都会被破坏"?由于"当屏幕方向改变时,系统会破坏并重新创建活动[...]". (5认同)
  • Cyrus - Nope,Activity确实被破坏了,它包含的Fragments在FragmentManager中被引用,而不仅仅是来自Activity,因此它保留并被读取. (4认同)
  • 在FragmentManager中查找后,记录片段onCreate和onDestroy方法及其哈希码清楚地显示片段IS被破坏.它只是重新创建并自动重新连接.只有当你将setRetainInstance(true)放在片段onCreate方法中时才会真正被破坏 (4认同)
  • 在 ViewPage 与 FragmentStatePagerAdapter 一起使用的情况下,如何处理相同的场景……有什么建议吗? (2认同)

k29*_*k29 83

引用本书 "为了确保一致的用户体验,Android在由于配置更改而重新启动Activity时会保留Fragment布局和关联的后台堆栈." (第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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是正确的答案,而不是标记的答案.非常感谢你! (10认同)
  • 你可能用这个节省了很多时间......非常感谢.您可以将此答案与Graeme中的答案结合起来,以获得处理配置更改和片段的完美解决方案. (2认同)
  • @SharpEdge 如果你有多个片段,你应该在添加到容器时给它们标签,然后使用 mFragmentManager.findFragmentByTag(而不是 findFragmentById)来获取对它们的引用 - 这样你就会知道每个片段的类并能够正确投射 (2认同)

Αλέ*_*κος 10

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

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

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