Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android oncreateview called twice

I have see this question asked here more than one time but I can't figure it out how to solve for my case.

I have an app that the user does this:

1 - Open the navigationDrawer and selects one option (a fragment is created) (I'm here selecting the second option);

public void selectItem(int position) {
        Fragment fragment = null;
        switch (position) {
            case FRAGMENT_OPTION1:
                ...
                break;
            case FRAGMENT_OPTION2:
                fragment = ControlPanelFragment.newInstance();
                break;
            ...
            case FRAGMENT_OPTIONN:
                ...
                return;
            default:
                break;
        }
        if (fragment != null) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            fragmentManager.beginTransaction().replace(R.id.fragment_container, fragment).commitAllowingStateLoss();
        }
}

2 - The selected option (ControlPanelFragment) gets loaded: 2.1 - Control panel has tabs and an iconpager. For each pager page and for each tab a new fragment is created. I have 3 tabs and 3 pages so 9 fragments are created;

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if (savedInstanceState != null) {
        currentControlPanelOption = savedInstanceState.getInt("currentControlPanelOption", currentControlPanelOption);
        currentControlPanelTab = savedInstanceState.getInt("currentControlPanelTab", currentControlPanelTab);
    }
    setControlPanelTabs();
    setIconPager();
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("currentControlPanelOption", pager.getCurrentItem());
    outState.putInt("currentControlPanelTab", mTabHost.getCurrentTab());
}

3 - In the setIconPager(); I have this code:

pager = (ViewPager) view.findViewById(R.id.pager);
cPanelPagerAdapter = new ControlPanelPagerAdapter(getChildFragmentManager());
pager.setOffscreenPageLimit(2);
pager.setAdapter(cPanelPagerAdapter);

where ControlPanelPagerAdapter has this code:

public Fragment getItem(int index) {
    Fragment fragment;
    switch (index) {
        case 1:
            fragment = FragmentA.newInstance();
            break;
        case 2:
            fragment = FragmentB.newInstance();
            break;
        case 3:
            fragment = FragmentC.newInstance();
            break;
        default:
            fragment = null;
            break;
    }
    ...
    return fragment;
}

4 - FragmentA, FragmentB and FragmentC have almost the same code:

public static FragmentA newInstance() {
    return new FragmentA();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_placeholder, container, false);
    return view;
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if (savedInstanceState == null) {
        fragmentA_Data = new FragmentADetail[3];
        createTabInstance(0);
    } else {
        fragmentA_Data = (FragmentADetail[]) savedInstanceState.getSerializable("Data");
        return;
    }
}
private void createTabInstance(int tab) {
    new FragmentADetail();
    fragment = FragmentADetail.newInstance(tab);

    Bundle args = new Bundle();
    args.putInt("tab", tab);
    fragment.setArguments(args);

    fragmentA_Data[tab] = fragment;
    FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
    fragmentTransaction.replace(R.id.fragment_placeholder, fragmentA_Data[tab]);
    fragmentTransaction.commitAllowingStateLoss();
}
public void getTabData(int tab) {
    if (fragmentA_Data[tab] == null) {
        createStoreTimePeriodInstance(tab);
    } else {
        if (fragmentA_Data[tab].getArguments() == null) {
            Bundle args = new Bundle();
            args.putInt("tab", tab);
            fragmentA_Data[tab].setArguments(args);
        }
        FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.fragment_placeholder, fragmentA_Data[tab]);
        fragmentTransaction.commitAllowingStateLoss();
    }
}
@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putSerializable("data", fragmentA_Data);
}

5 - Finally, FragmentADetail has this code:

public static FragmentADetail newInstance(int tab) {
    selectedTab = tab;
    return new FragmentADetail();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.details_fragment, container, false);
    ...
    if (savedInstanceState != null) {
        selectedTab = savedInstanceState.getInt("selectedTab");
    }
    ...
}

public void getTabData(int tab) {
    //This is where I'm getting the data that populates the layout
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("selectedTab", selectedTab);
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    Bundle args = getArguments();
    if (args != null) {
       getTabData(args.getInt("tab"));
    }
}

Now, imagine I'm on FragmentA with the third tab selected. If I rotate the screen I have this sequence of events:

  1. ControlPanelFragment onSaveInstanceState saves the current tab and current fragment
  2. FragmentA onSaveInstanceState saves the tabs fragments for the pager
  3. navigationDrawer second option gets again called fragment = ControlPanelFragment.newInstance();
  4. ControlPanelFragment onViewCreated is called and I can get the saved data information and a new pager and tabs are created
  5. FragmentA onViewCreated is called and I can extract the saved data
  6. FragmentADetail onActivityCreated gets the saved data and loads the data correctelly (at least I think) And from now a second set of methods is called the second time and the data that was previously saved is reseted and so it now displays wrong data
  7. ControlPanelFragment onSaveInstanceState but now the savedInstanceState is null
  8. ControlPanelPagerAdapter getItem is called instantiating the 3 fragments
  9. FragmentA onSaveInstanceState its now called but savedInstanceState is null
  10. FragmentADetail onActivityCreated is called but now the tab = 0

Can someone explain-me how can I stop steps 7 to 10 from happening?

like image 400
Favolas Avatar asked Dec 31 '14 16:12

Favolas


1 Answers

I figure out what was my problem.

When I was doing:

case FRAGMENT_OPTION2:
    fragment = ControlPanelFragment.newInstance();
break;

I was creating a fragment and when I rotated the screen selectItem(int position) was again called so a new instance of the same object was created thus the steps 7 and following. The solution was to check if the fragment was already created and use him instead of creating a new one. I've saved the initial fragment with a tag and them looked for that tag. If the tag existed, use that fragment otherwise create a new one.

public void selectItem(int position) {
        Fragment fragment = null;
        switch (position) {
            case FRAGMENT_OPTION1:
                ...
                break;
            case FRAGMENT_OPTION2:
                fragment = getSupportFragmentManager().findFragmentByTag(String.valueOf(position));
                if (fragment == null) {
                    fragment = ControlPanelFragment.newInstance();
                }
                break;
            ...
            case FRAGMENT_OPTIONN:
                ...
                return;
            default:
                break;
        }
        if (fragment != null) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            fragmentManager.beginTransaction().replace(R.id.fragment_container, fragment, 
                    String.valueOf(position)).commitAllowingStateLoss();
        }
}
like image 86
Favolas Avatar answered Oct 22 '22 13:10

Favolas