活动和片段的生命周期及方向更改

13

我最近遇到了一些有关Fragments和屏幕旋转的奇怪问题,导致应用崩溃并且不符合逻辑。

于是我写了一个简单的ActivityFragment生命周期调试应用程序,它通过记录每个步骤到logcat来实现了Activity生命周期Fragment生命周期的所有过程。

这里是TestActivityTestFragment类:

TestActivity

public class TestActivity extends Activity {
    Context ct = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Log.e("ACT", "onCreate called");

        ct = getApplicationContext();

        FrameLayout fl = new FrameLayout(ct);
        fl.setId(1000);

        TestFragment tf = new TestFragment();
        getFragmentManager().beginTransaction().add(fl.getId(), tf, "").commit();

        setContentView(fl);
    }

    @Override
    protected void onStart() {
        Log.e("ACT", "onStart called");
        super.onStart();
    }

    @Override
    protected void onResume() {
        Log.e("ACT", "onResume called");
        super.onResume();
    }

    @Override
    protected void onPause() {
        Log.e("ACT", "onPause called");
        super.onPause();
    }

    @Override
    protected void onStop() {
        Log.e("ACT", "onStop called");
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        Log.e("ACT", "onDestroy called");
        super.onDestroy();
    }

    @Override
    protected void onRestart() {
        Log.e("ACT", "onRestart called");
        super.onRestart();
    }
}

测试片段

public class TestFragment extends Fragment {
    Context ctFrag = null;

    @Override
    public void onAttach(Activity activity) {
        Log.e("FRAG", "onAttach called");
        super.onAttach(activity);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Log.e("FRAG", "onCreate called");

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        Log.e("FRAG", "onCreateView called");

        ctFrag = ((TestActivity) getActivity()).ct;

        TextView tv = new TextView(ctFrag);
        tv.setText("My test TextView");

        return tv;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        Log.e("FRAG", "onActivityCreated called");
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onStart() {
        Log.e("FRAG", "onStart called");
        super.onStart();
    }

    @Override
    public void onResume() {
        Log.e("FRAG", "onResume called");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.e("FRAG", "onPause called");
        super.onPause();
    }

    @Override
    public void onStop() {
        Log.e("FRAG", "onStop called");
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        Log.e("FRAG", "onDestroyView called");
        super.onDestroyView();
    }

    @Override
    public void onDestroy() {
        Log.e("FRAG", "onDestroy called");
        super.onDestroy();
    }

    @Override
    public void onDetach() {
        Log.e("FRAG", "onDetach called");
        super.onDetach();
    }
}

初始化时,Logcat 的输出按照预期的顺序进行(启动Activity,当 Fragment 被附加时,其生命周期的调用发生等):

01-29 10:12:50.270: E/ACT(3321): onCreate called
01-29 10:12:50.760: E/FRAG(3321): onAttach called
01-29 10:12:50.760: E/FRAG(3321): onCreate called
01-29 10:12:50.760: E/FRAG(3321): onCreateView called
01-29 10:12:50.770: E/FRAG(3321): onActivityCreated called
01-29 10:12:50.770: E/ACT(3321): onStart called
01-29 10:12:50.770: E/FRAG(3321): onStart called
01-29 10:12:50.770: E/ACT(3321): onResume called
01-29 10:12:50.770: E/FRAG(3321): onResume called

然而问题是,当发生方向变化时,Android文档说:

当这种变化发生时,Android会重新启动运行中的Activity(调用onDestroy(),然后调用onCreate())。

这表明它应该关闭Activity和其内容,就像生命周期建议的那样(它确实这样做)。但是随后它并没有按照同样的顺序过程重新创建新方向的Activity。相反,它似乎尝试重新创建Fragment,然后在活动重新创建时再创建一个新的Fragment

01-29 10:17:52.249: E/FRAG(3321): onPause called
01-29 10:17:52.259: E/ACT(3321): onPause called
01-29 10:17:52.269: E/FRAG(3321): onStop called
01-29 10:17:52.269: E/ACT(3321): onStop called
01-29 10:17:52.279: E/FRAG(3321): onDestroyView called
01-29 10:17:52.299: E/FRAG(3321): onDestroy called
01-29 10:17:52.299: E/FRAG(3321): onDetach called
01-29 10:17:52.299: E/ACT(3321): onDestroy called
01-29 10:17:52.650: E/FRAG(3321): onAttach called
01-29 10:17:52.650: E/FRAG(3321): onCreate called
01-29 10:17:52.650: E/ACT(3321): onCreate called
01-29 10:17:53.020: E/FRAG(3321): onCreateView called
01-29 10:17:53.020: E/FRAG(3321): onActivityCreated called
01-29 10:17:53.030: E/FRAG(3321): onAttach called
01-29 10:17:53.030: E/FRAG(3321): onCreate called
01-29 10:17:53.030: E/FRAG(3321): onCreateView called
01-29 10:17:53.030: E/FRAG(3321): onActivityCreated called
01-29 10:17:53.060: E/ACT(3321): onStart called
01-29 10:17:53.060: E/FRAG(3321): onStart called
01-29 10:17:53.060: E/FRAG(3321): onStart called
01-29 10:17:53.060: E/ACT(3321): onResume called
01-29 10:17:53.060: E/FRAG(3321): onResume called
01-29 10:17:53.060: E/FRAG(3321): onResume called
显然有很多解决方案可以解决这个问题,但我的问题是为什么会发生这种情况?为什么一个“Fragment”引用在应该被销毁并重新创建的“Activity”中被保留和重新创建?我可以通过“Fragment”有意地与活动分开来证明这一点。但是导致问题的原因是,“Activity”之前为什么会先重新连接和重新创建原始的“Fragment”?这似乎不遵循Android进程的逻辑生命周期的其他部分。
2个回答

10
这是因为活动在被销毁之前调用了 onSaveInstanceState(Bundle)。默认情况下,该活动在此方法中保存其片段的状态。
稍后,当活动被重新创建时,旧的碎片将在活动的 onCreate(Bundle savedInstanceState) 方法中被重新创建。
您可能需要检查源代码这里这里以更好地理解此行为。

3
没错,谢谢。我的问题似乎只取决于我在onCreate调用中何时调用super.onCreate()。现在我确切地知道了为什么会发生这种情况,我可以解决它了,谢谢。 - btalb

1

这是因为在活动重新创建时,您不断地添加片段。您可以在活动的onCreate方法中使用以下代码来避免重新创建片段:

if(savedInstanceState == null) 
{
    mFragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();

    FragmentOne fragment = new FragmentOne();

    fragmentTransaction.add(R.id.fragment_container, fragment);
    fragmentTransaction.commit();
}

当配置更改发生时,旧的 Fragment 不会被销毁——它会在重新创建时将自己添加回 Activity。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接