Активность и фрагментация жизненных циклов и изменения ориентации

У меня были очень странные проблемы с Fragments и изменениями ориентации, которые вызывали силу, закрывающуюся и не следуя логическому шаблону.

Я создал простое приложение для отладки жизненного цикла Activity и Fragment, которое просто реализует каждый шаг жизненного цикла деятельности и Жизненный цикл фрагмента, сообщая о вызове логарифма.

Вот классы TestActivity и TestFragment:

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

TestFragment

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 следует ожидаемому порядку (start 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 перезапустит текущую активность (вызывается onDestroy(), а затем onCreate())

Что бы предположить, что он должен отключить Activity, и его содержимое, как и жизненный цикл, предлагает (и это делает), но затем пройдите через тот же упорядоченный процесс, воссоздающий Activity в новой ориентации. Этот не работает, и кажется, что 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 намеренно разделяет действия. Но что вызвало проблемы, почему является исходным Fragment прикрепленным и воссозданным до Activity? Похоже, что он не соответствует логическому жизненному циклу, который выполняет остальная часть процесса Android.

Ответ 1

Это происходит потому, что активность вызывает onSaveInstanceState(Bundle) перед уничтожением. По умолчанию эта функция сохраняет состояния своих фрагментов в этом методе.

Позже, когда активность будет воссоздана, старые фрагменты воссоздаются в методе onCreate(Bundle savedInstanceState).

Здесь вы можете проверить исходный код здесь и здесь, чтобы лучше понять это поведение.

Ответ 2

Это связано с тем, что вы добавляете фрагмент снова и снова в процессе воссоздания. Вы можете использовать приведенный ниже код в действии onCreate, чтобы избежать воссоздания фрагмента:

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

    FragmentOne fragment = new FragmentOne();

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

При изменении конфигурации старый фрагмент не уничтожается - он снова добавляет себя в действие, когда он воссоздается.