Страница 1 из 1

Фрагменты и жизненный цикл. Немного магии.

Добавлено: 13 ноя 2013, 01:33
Mikhail_dev
Поворот экрана. А что будет с фрагментом, если ему стоит флаг setRetainInstance(true)? А если false? А если мы удалим перед поворотом фрагмент? Или при старте? Или в обоих местах? replace использовать или add?
Да какая разница... Пациент быстрее жив, чем мертв.
Код фрагмента. Тут просто будем выводить в консоль его жизненный цикл
[syntax=java5]
public class MyFragment extends Fragment {

@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.d("sample", "Fragment onAttach "+this);
}

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("sample", "Frag onCreate "+this);
}

public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragment = inflater.inflate(R.layout.fragment, null);
Log.d("sample", "Frag onCreateView " + this);
return fragment;
}

public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d("sample", "Frag onActivityCreated "+this);
}

public void onStart() {
super.onStart();
Log.d("sample", "Frag onStart "+this);
}

public void onResume() {
super.onResume();
Log.d("sample", "Frag onResume "+this);
}

public void onPause() {
super.onPause();
Log.d("sample", "Frag onPause "+this);
}

public void onStop() {
super.onStop();
Log.d("sample", "Frag onStop "+this);
}

public void onDestroyView() {
super.onDestroyView();
Log.d("sample", "Frag onDestroyView "+this);
}

public void onDestroy() {
super.onDestroy();
Log.d("sample", "Frag onDestroy "+this);
}

public void onDetach() {
super.onDetach();
Log.d("sample", "Frag onDetach "+this);
}
}
[/syntax]
Допустим наше желание НЕ сохранять фрагмент при повороте. Когда такое может понадобиться. К примеру, если у вас есть ViewPager, который является фрагментом, а в нем еще несколько фрагментов. А теперь добавьте сюда логики, к примеру, в ландшафте располагать 2 фрагмента, а в портрете один. Тут сохранение идет лесом. Закончим лирическое отступление.
Код активности. Будем его по мере необходимости изменять
[syntax=java5]
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("sample", "MainActivity onStart");

MyFragment myFragment = new MyFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.main_frame, myFragment);
transaction.commit();
}

protected void onStart() {
super.onStart();
Log.d("sample", "MainActivity onStart");
}

protected void onResume() {
super.onResume();
Log.d("sample", "MainActivity onResume");
}

protected void onPause() {
super.onPause();
Log.d("sample", "MainActivity onPause");
}

protected void onStop() {
super.onStop();
Log.d("sample", "MainActivity onStop");
}

protected void onDestroy() {
super.onDestroy();
Log.d("sample", "MainActivity onDestroy");
}
}[/syntax]
Я добавил специально transaction.add, дабы показать разницу. Итак, консоль
Всегда создаем фрагмент в onCreate. Жизненный цикл до onResume.
MainActivity onStart
Fragment onAttach MyFragment{416a46e8 #0 id=0x7f080000}
Frag onCreate MyFragment{416a46e8 #0 id=0x7f080000}
Frag onCreateView MyFragment{416a46e8 #0 id=0x7f080000}
Frag onActivityCreated MyFragment{416a46e8 #0 id=0x7f080000}
Frag onStart MyFragment{416a46e8 #0 id=0x7f080000}
MainActivity onStart
MainActivity onResume
Frag onResume MyFragment{416a46e8 #0 id=0x7f080000}
Frag onPause MyFragment{416a46e8 #0 id=0x7f080000}
MainActivity onPause
MainActivity onResume
Frag onResume MyFragment{416a46e8 #0 id=0x7f080000}
Кстати замечу, что в фигурных скобках информация об объекте фрагмента {адрес памяти, номер фрагмента в стеке, на сколько понял, id контейнера}
Всё красиво, всё правильно. Поворачиваем экран.
11-13 01:57:05.944: D/sample(19366): Frag onPause MyFragment{416a46e8 #0 id=0x7f080000}
11-13 01:57:05.944: D/sample(19366): MainActivity onPause
11-13 01:57:05.944: D/sample(19366): Frag onStop MyFragment{416a46e8 #0 id=0x7f080000}
11-13 01:57:05.944: D/sample(19366): MainActivity onStop
11-13 01:57:05.944: D/sample(19366): Frag onDestroyView MyFragment{416a46e8 #0 id=0x7f080000}
11-13 01:57:05.954: D/sample(19366): Frag onDestroy MyFragment{416a46e8 #0 id=0x7f080000}
11-13 01:57:05.954: D/sample(19366): Frag onDetach MyFragment{416a46e8 #0 id=0x7f080000}
11-13 01:57:05.954: D/sample(19366): MainActivity onDestroy
11-13 01:57:06.084: D/sample(19366): Fragment onAttach MyFragment{416f9e48 #0 id=0x7f080000}
11-13 01:57:06.084: D/sample(19366): Frag onCreate MyFragment{416f9e48 #0 id=0x7f080000}
11-13 01:57:06.154: D/sample(19366): MainActivity onStart
11-13 01:57:06.154: D/sample(19366): Frag onCreateView MyFragment{416f9e48 #0 id=0x7f080000}
11-13 01:57:06.164: D/sample(19366): Frag onActivityCreated MyFragment{416f9e48 #0 id=0x7f080000}
11-13 01:57:06.164: D/sample(19366): Fragment onAttach MyFragment{41703da8 #1 id=0x7f080000}
11-13 01:57:06.164: D/sample(19366): Frag onCreate MyFragment{41703da8 #1 id=0x7f080000}
11-13 01:57:06.174: D/sample(19366): Frag onCreateView MyFragment{41703da8 #1 id=0x7f080000}
11-13 01:57:06.174: D/sample(19366): Frag onActivityCreated MyFragment{41703da8 #1 id=0x7f080000}
11-13 01:57:06.174: D/sample(19366): Frag onStart MyFragment{416f9e48 #0 id=0x7f080000}
11-13 01:57:06.174: D/sample(19366): Frag onStart MyFragment{41703da8 #1 id=0x7f080000}
11-13 01:57:06.174: D/sample(19366): MainActivity onStart
11-13 01:57:06.194: D/sample(19366): MainActivity onResume
11-13 01:57:06.194: D/sample(19366): Frag onResume MyFragment{416f9e48 #0 id=0x7f080000}
11-13 01:57:06.194: D/sample(19366): Frag onResume MyFragment{41703da8 #1 id=0x7f080000}
Особо интересное я выделил жирным. До onCreate вылез наш фрагмент. А дальше вы можете лицезреть ДВА фрагмента с одной РАЗНЫМИ областями памяти, 416f9e48 и 41703da8.
Ну хорошо, давайте теперь поставим replace вместо add.
[syntax=java5]
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("sample", "MainActivity onStart");

MyFragment myFragment = new MyFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_frame, myFragment);
transaction.commit();
}
[/syntax]
При старте всё нормально. Буду показывать только при повороте
11-13 02:02:19.694: D/sample(20012): Frag onPause MyFragment{416a4dd8 #0 id=0x7f080000}
11-13 02:02:19.694: D/sample(20012): MainActivity onPause
11-13 02:02:19.704: D/sample(20012): Frag onStop MyFragment{416a4dd8 #0 id=0x7f080000}
11-13 02:02:19.704: D/sample(20012): MainActivity onStop
11-13 02:02:19.704: D/sample(20012): Frag onDestroyView MyFragment{416a4dd8 #0 id=0x7f080000}
11-13 02:02:19.704: D/sample(20012): Frag onDestroy MyFragment{416a4dd8 #0 id=0x7f080000}
11-13 02:02:19.704: D/sample(20012): Frag onDetach MyFragment{416a4dd8 #0 id=0x7f080000}
11-13 02:02:19.704: D/sample(20012): MainActivity onDestroy
11-13 02:02:19.774: D/sample(20012): Fragment onAttach MyFragment{416b7530 #0 id=0x7f080000}
11-13 02:02:19.784: D/sample(20012): Frag onCreate MyFragment{416b7530 #0 id=0x7f080000}
11-13 02:02:19.844: D/sample(20012): MainActivity onStart
11-13 02:02:19.854: D/sample(20012): Frag onCreateView MyFragment{416b7530 #0 id=0x7f080000}
11-13 02:02:19.854: D/sample(20012): Frag onActivityCreated MyFragment{416b7530 #0 id=0x7f080000}
11-13 02:02:19.854: D/sample(20012): Frag onDestroyView MyFragment{416b7530 #0 id=0x7f080000}
11-13 02:02:19.864: D/sample(20012): Frag onDestroy MyFragment{416b7530 #0 id=0x7f080000}
11-13 02:02:19.864: D/sample(20012): Frag onDetach MyFragment{416b7530 #0 id=0x7f080000}
11-13 02:02:19.864: D/sample(20012): Fragment onAttach MyFragment{416c1490 #0 id=0x7f080000}
11-13 02:02:19.864: D/sample(20012): Frag onCreate MyFragment{416c1490 #0 id=0x7f080000}
11-13 02:02:19.864: D/sample(20012): Frag onCreateView MyFragment{416c1490 #0 id=0x7f080000}
11-13 02:02:19.874: D/sample(20012): Frag onActivityCreated MyFragment{416c1490 #0 id=0x7f080000}
11-13 02:02:19.874: D/sample(20012): Frag onStart MyFragment{416c1490 #0 id=0x7f080000}
11-13 02:02:19.874: D/sample(20012): MainActivity onStart
11-13 02:02:19.874: D/sample(20012): MainActivity onResume
11-13 02:02:19.884: D/sample(20012): Frag onResume MyFragment{416c1490 #0 id=0x7f080000}
Жирным я выделил область памяти сохранившегося фрагмента. Посмотрите, какие он проходит жизненные циклы.
onAttach
onCreate
onCreateView
onActivityCreated
onDestroyView
onDestroy

Более того, если я создам фрагмент к примеру в жизненном цикле активности onStart или onReume, то данный фрагмент пройдет еще больше жизненных циклов.
Попробуем удалить. Добавим метод удаления фрагмента по ID контейнера в onCreate активити.
[syntax=java5]
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("sample", "MainActivity onStart");

MyFragment myFragment = (MyFragment) getSupportFragmentManager().findFragmentById(R.id.main_frame);
if (myFragment!=null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.remove(myFragment);
myFragment = null;
ft.commit();
Log.d("sample", "Removed in onCreate");
}

myFragment = new MyFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_frame, myFragment);
transaction.commit();
}

protected void onStart() {
super.onStart();
Log.d("sample", "MainActivity onStart");
}

protected void onResume() {
super.onResume();
Log.d("sample", "MainActivity onResume");
}

protected void onPause() {
super.onPause();
Log.d("sample", "MainActivity onPause");
}

protected void onStop() {
super.onStop();
Log.d("sample", "MainActivity onStop");
}

@Override
protected void onDestroy() {
super.onDestroy();
}
}
[/syntax]
Получим
11-13 02:11:26.684: D/sample(20780): Frag onPause MyFragment{416a1df0 #0 id=0x7f080000}
11-13 02:11:26.684: D/sample(20780): MainActivity onPause
11-13 02:11:26.694: D/sample(20780): Frag onStop MyFragment{416a1df0 #0 id=0x7f080000}
11-13 02:11:26.694: D/sample(20780): MainActivity onStop
11-13 02:11:26.694: D/sample(20780): Frag onDestroyView MyFragment{416a1df0 #0 id=0x7f080000}
11-13 02:11:26.694: D/sample(20780): Frag onDestroy MyFragment{416a1df0 #0 id=0x7f080000}
11-13 02:11:26.694: D/sample(20780): Frag onDetach MyFragment{416a1df0 #0 id=0x7f080000}
11-13 02:11:26.744: D/sample(20780): Fragment onAttach MyFragment{416b5538 #0 id=0x7f080000}
11-13 02:11:26.744: D/sample(20780): Frag onCreate MyFragment{416b5538 #0 id=0x7f080000}
11-13 02:11:26.784: D/sample(20780): MainActivity onStart
11-13 02:11:26.784: D/sample(20780): Removed in onCreate
11-13 02:11:26.794: D/sample(20780): Frag onCreateView MyFragment{416b5538 #0 id=0x7f080000}
11-13 02:11:26.794: D/sample(20780): Frag onActivityCreated MyFragment{416b5538 #0 id=0x7f080000}
11-13 02:11:26.794: D/sample(20780): Frag onDestroyView MyFragment{416b5538 #0 id=0x7f080000}
11-13 02:11:26.794: D/sample(20780): Frag onDestroy MyFragment{416b5538 #0 id=0x7f080000}
11-13 02:11:26.794: D/sample(20780): Frag onDetach MyFragment{416b5538 #0 id=0x7f080000}
11-13 02:11:26.794: D/sample(20780): Fragment onAttach MyFragment{416bf5e0 #0 id=0x7f080000}
11-13 02:11:26.794: D/sample(20780): Frag onCreate MyFragment{416bf5e0 #0 id=0x7f080000}
11-13 02:11:26.794: D/sample(20780): Frag onCreateView MyFragment{416bf5e0 #0 id=0x7f080000}
11-13 02:11:26.794: D/sample(20780): Frag onActivityCreated MyFragment{416bf5e0 #0 id=0x7f080000}
11-13 02:11:26.794: D/sample(20780): Frag onStart MyFragment{416bf5e0 #0 id=0x7f080000}
11-13 02:11:26.794: D/sample(20780): MainActivity onStart
11-13 02:11:26.804: D/sample(20780): MainActivity onResume
11-13 02:11:26.804: D/sample(20780): Frag onResume MyFragment{416bf5e0 #0 id=0x7f080000}
И получаем, что фрагмент не может удалиться. Он прошел свои жизненные циклы, умер и после создан был новый. Замечу, замечу, что до поворота и после поворота, все экземпляры (до поворота один и после поворота два) - разные объекты. Так что не думайте, что область памяти у этого глючного фрагмента, что появляется после поворота, будет того, что до поворота.
Решить проблему я смог, очень стандартно, но не так, как хотелось бы
[syntax=java5]
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

myFragment = (MyFragment) getSupportFragmentManager().findFragmentById(R.id.main_frame);
if (myFragment==null) {
myFragment = new MyFragment();
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_frame, myFragment);
transaction.commit();
}
[/syntax]
Т.е. ищите фрагмент всегда, даже если вы ничего не сохраняете.
11-13 02:21:26.044: D/sample(21645): Frag onPause MyFragment{416a7c78 #0 id=0x7f080000}
11-13 02:21:26.044: D/sample(21645): MainActivity onPause
11-13 02:21:26.044: D/sample(21645): Frag onStop MyFragment{416a7c78 #0 id=0x7f080000}
11-13 02:21:26.044: D/sample(21645): MainActivity onStop
11-13 02:21:26.064: D/sample(21645): Frag onDestroyView MyFragment{416a7c78 #0 id=0x7f080000}
11-13 02:21:26.064: D/sample(21645): Frag onDestroy MyFragment{416a7c78 #0 id=0x7f080000}
11-13 02:21:26.064: D/sample(21645): Frag onDetach MyFragment{416a7c78 #0 id=0x7f080000}
11-13 02:21:26.154: D/sample(21645): Fragment onAttach MyFragment{416b8e98 #0 id=0x7f080000}
11-13 02:21:26.154: D/sample(21645): Frag onCreate MyFragment{416b8e98 #0 id=0x7f080000}
11-13 02:21:26.194: D/sample(21645): Frag onCreateView MyFragment{416b8e98 #0 id=0x7f080000}
11-13 02:21:26.194: D/sample(21645): Frag onActivityCreated MyFragment{416b8e98 #0 id=0x7f080000}
11-13 02:21:26.204: D/sample(21645): Frag onStart MyFragment{416b8e98 #0 id=0x7f080000}
11-13 02:21:26.204: D/sample(21645): MainActivity onStart
11-13 02:21:26.204: D/sample(21645): MainActivity onResume
11-13 02:21:26.204: D/sample(21645): Frag onResume MyFragment{416b8e98 #0 id=0x7f080000}
Если вкратце, то при повороте экрана, фрагменты всегда сохраняются, так что вы можете даже с transaction.replace получить memory leak. Речь идёт про динамически добавленные фрагменты. Статические итак не удаляются
Материалы по теме:
Вырезка с книги Professional Android 4 Application Development (Wrox Professional Guides)
"to ensure a consistent user experience, Android persists the Fragment layout and associated back stack when an Activity is restarted due to a configuration change." (p. 124)
Dynamically added fragments are not removed when the container is removed
Android Fragment lifecycle over orientation changes
Fragment/Activity Lifecycles and Orientation Change
Weird fragment lifecycle error

Re: Фрагменты и жизненный цикл. Немного магии.

Добавлено: 11 авг 2014, 01:34
парень
Провозился более суток с удалением фрагментов...

Задача была такова:

Есть 3 фрагмента main, в каждом есть ViewPager с фрагментами...
При смене main фрагмента (по боковому меню) методом replace, количество фрагментов росло... Т.е. те фрагменты что создавались адаптером для ViewPager'a не удалялись из памяти и плодились до безобразия...

Решение же оказалось для меня внезапно удивляющим...

Вместо [syntax=java5]pagerAdapter = new MyFragmentPagerAdapter(geFragmentManager());[/syntax]
написал так:
[syntax=java5]pagerAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());[/syntax]

Теперь фрагменты не плодятся...

Re: Фрагменты и жизненный цикл. Немного магии.

Добавлено: 11 авг 2014, 08:15
Mikhail_dev
Вообще для меня вопрос, как программа вообще работала. У меня она падала, когда я не использовал getChildFragmentManager во вложенных фрагментах.
Чтобы находить утечки, советую всё же поучить немного инструмент MAT (Memory Analizer Tool). Я так о нем и не выпустил статью, хотя он и только он мне помог выявить утечки памяти в моей программе. Ту статью, что я написал на хабре, она больше к оптимизации кода и к пониманию, что работает медленно.

Re: Фрагменты и жизненный цикл. Немного магии.

Добавлено: 11 авг 2014, 08:42
altwin
Mikhail_dev писал(а): Я так о нем и не выпустил статью
Ну вот нашли причину всех бед... :)

Re: Фрагменты и жизненный цикл. Немного магии.

Добавлено: 11 авг 2014, 09:43
Mikhail_dev
Честно говоря, я не понял что ты сказал.
Я в своей статье на хабре обещал рассмотреть в дальнейшем MAT и написать статью по нему. Об этом и сказал.

Re: Фрагменты и жизненный цикл. Немного магии.

Добавлено: 11 авг 2014, 11:51
парень
Mikhail_dev писал(а):Вообще для меня вопрос, как программа вообще работала. У меня она падала, когда я не использовал getChildFragmentManager во вложенных фрагментах.
Работала на 2.х и 4.х, на двух реальных и 3 виртуальных устройствах... Также у тестеров все работало, и кстати работает у более чем 10 тысяч пльзователей в релиз версии...
Чтобы находить утечки, советую всё же поучить немного инструмент MAT (Memory Analizer Tool). Я так о нем и не выпустил статью, хотя он и только он мне помог выявить утечки памяти в моей программе. Ту статью, что я написал на хабре, она больше к оптимизации кода и к пониманию, что работает медленно.
А ведь обещал написать ))) Спасибо, посмотрю что это такое...

Re: Фрагменты и жизненный цикл. Немного магии.

Добавлено: 11 авг 2014, 11:53
парень
Кстати, пока возился с удалением фрагментов, пробовал что-то такое: getFragmentManager().getFragments().remove(1) - или .clear(); Так и не понял - сам фрагмент удаляется из памяти, или только из списка фрагментов? )))

Re: Фрагменты и жизненный цикл. Немного магии.

Добавлено: 11 авг 2014, 12:07
Mikhail_dev
Он как бы кешируется, чтобы можно было потом его показать. В принципе это вполне нормально. Считай это пулом фрагментов. Они как бы полумертвые, пустые, но созданные.

Re: Фрагменты и жизненный цикл. Немного магии.

Добавлено: 01 апр 2017, 22:58
nobody
Извините за апание старой темы.
Проблема следующая - фрагменты экстендится от abstract class AbstractTabFragment

Код: Выделить всё

public abstract class AbstractTabFragment extends Fragment {
    private String title;
    protected Context context;
    protected View view;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}
который содержит поле protected Context context. Именно при повороте устройства значение этого поля становится null.

Класс адаптер для табов

Код: Выделить всё

import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.view.ViewGroup;

import java.util.HashMap;
import java.util.Map;

import ru.rassvetmedia.totalconrolbeta.fragments.AbstractTabFragment;
import ru.rassvetmedia.totalconrolbeta.fragments.AccountsFragment;
import ru.rassvetmedia.totalconrolbeta.fragments.ReportFragment;


public class TabsPagerAdapter extends FragmentPagerAdapter {
    private Map<Integer, AbstractTabFragment> tabs;
    private Context context;

    public TabsPagerAdapter(Context context, FragmentManager fm) {
        super(fm);
        this.context = context;
        initFragments(context);

    }

    @Override
    public CharSequence getPageTitle(int position) {
        return tabs.get(position).getTitle();
    }

    @Override
    public Fragment getItem(int position) {
        return tabs.get(position);

    }

    @Override
    public int getCount() {
        return tabs.size();
    }

    private void initFragments(Context context) {
        this.tabs = new HashMap<>();
        tabs.put(0, AccountsFragment.getInstance(context));
        tabs.put(1, ReportFragment.getInstance(context));
    }
}
Код (фрагмент кода) фрагмента, где собственно и происходит падение:

Код: Выделить всё

@Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        db = GetSQLiteOpenHelper.getHelperInstance(this.context);
        db.getWritableDatabase();

        final View rootView = inflater.inflate(LAYOUT, container, false);

        infos = new AndroidListAccountsViewModel(this.context);
        ListView lv = (ListView) rootView.findViewById(R.id.listView);
        infos.setLv(lv).setContext(this.context);
        scAdapter = new SimpleCursorAdapter(this.context, R.layout.list_item, null, from, to, 0);
        lv.setAdapter(scAdapter);

        fab = (FloatingActionButton) rootView.findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            public void onClick(View rootView) {
                Log.d(Constans.LOG_TAG, "FloatingActionButton onClick");
                openDialogFirstSettingsApp();
            }
        });

        getLoaderManager().initLoader(0, null, this);
        return rootView;
    }
Почему?

Re: Фрагменты и жизненный цикл. Немного магии.

Добавлено: 24 май 2021, 08:22
shephord
парень писал(а):
11 авг 2014, 01:34
Провозился более суток с удалением фрагментов...

Задача была такова:

Есть 3 фрагмента main, в каждом есть ViewPager с фрагментами...
При omegle смене main фрагмента (по боковому меню) методом replace, количество фрагментов росло... Т.е. те фрагменты что создавались адаптером для ViewPager'a не удалялись из памяти и chat плодились до безобразия...

Решение же оказалось для меня внезапно удивляющим...

Вместо [syntax=java5]pagerAdapter = new MyFragmentPagerAdapter(geFragmentManager());[/syntax]
написал так:
[syntax=java5]pagerAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());[/syntax]

Теперь фрагменты не плодятся...
Hey, Excellent way of explanation.
I got everything easily.