9

So here is my code. 'currentFragment' is simply a field that tracks what is currently being displayed. This is in a class that itself is a Fragment (so I have a fragment showing a fragment).

private void selectNavBarItem(NavbarItem v)
{
    Fragment fragmentToUse = null;

    if (v == setpointsNavItem)
    {
        fragmentToUse = setpointsFragment;
    }
    else if (v == rapidSetupNavItem)
    {
        fragmentToUse = rapidSetupFragment;
    }
    else if (v == outdoorResetNavItem)
    {
        fragmentToUse = outdoorResetFragment;
    }
    else if (v == rampDelayNavItem)
    {
        fragmentToUse = rampDelayFragment;
    }

    if (fragmentToUse != null)
    {
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();

        if (currentFragment != null)
        {
            ft.detach(currentFragment);
        }

        currentFragment = fragmentToUse;

        if (currentFragment.isDetached())
        {
            ft.attach(currentFragment);
        }
        else
        {
            ft.add(R.id.setup_content_holder, currentFragment);
        }

        ft.addToBackStack(null);
        ft.commit();
    }

Everything looks great, but the views are getting recreated for all the fragments (onCreateView() and onViewCreated()). I was hoping that attaching and detaching would work, but it doesn't. The reason I want to maintain the view is so the user's selections are still there when they navigate back.

Another option is showing and hiding, but I don't know how to make that work because the fragment that owns this code has a FrameLayout (R.id.setup_content_holder) that holds the fragment I want to add, and I can't just add four fragments to it but hide three of them. There is an option to add a fragment with no container, but I have no idea how that is supposed to work.

So, any ideas?

Mark Herscher
  • 1,761
  • 2
  • 19
  • 32

3 Answers3

10

Try this, this will solve your frgment view r-creating issue;

 @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (mFragmentView != null) {
            ((ViewGroup) mFragmentView.getParent()).removeView(mFragmentView);
            return mFragmentView;
        }

        mFragmentView = inflater.inflate(R.layout.home_fragment, container, false);

        ..... // your remaining code 
}
Pawan Maheshwari
  • 15,088
  • 1
  • 48
  • 50
1

The OnCreateView methods are always called within a Fragment.

To solve the problem you're describing what you really need to do is save the state of the fragment, then when it returns the application will restore what you saved.

e.g. (within the fragment class in question):

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceStatePutString("userString", someTextView.getText().toString());
    savedInstanceStatePutInt("userInt", userInt);
    // etc...
}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    someTextView.setText(savedInstanceState.getString("userString"));
    userInt = savedInstanceState.getInt("userInt");
}

That should solve your problem while hopping between fragments; the application will call onSaveInstanceState and onRestoreInstanceState when a fragment gets pushed into or pulled out of the stack.

It will not save them forever, however! If you need more persistent storage, look into other options such as saving to a sqlite database.

NateCron
  • 13
  • 3
  • 1
    Ugh, I don't want to use Bundles - they are a lot of maintenance if I modify fields, not to mention the lack of compile-time checking. No offense to your answer - I'm sure it's how Android wants me to do it. Do you know if my new approach (see my new answer) is a good idea? – Mark Herscher Jan 14 '14 at 16:57
1

OP here.

So I hacked something together here, and I'm wondering if it's a good idea. I have a Fragment holding a View. The View contains everything I want to save (in the short term, of course - this isn't supposed to be any more persistent than RAM). When the Fragment calls onCreateView() I simply return the already-created View.

Now, I ran into an issue where the View was not being removed by the fragment manager. I added a call in onPause() to make sure it's removed from the parent.

Everything seems to work fine, but I want to make sure I'm not doing something really bad. I know Android really really wants to manage its view lifecycles itself, but I do not want it recreating them every damn time. They are complicated and I don't want to deal with re-initializing all the subview text/image/state. Will I run into issues in my attempt to do a run-around Android's normal operating procedure?

EDIT: forgot the code:

public class OutdoorResetFragment extends Fragment
{
private OutdoorResetView view;

public OutdoorResetFragment()
{

}

public void onAttach(Activity activity)
{
    if (view == null || view.getContext() != activity)
    {
        view = new OutdoorResetView(activity);
    }

    super.onAttach(activity);
}

public void onPause()
{
    super.onPause();

    ViewGroup container = (ViewGroup) view.getParent();

    if (container != null)
    {
        container.removeAllViews();
    }
}

@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
        final Bundle savedInstanceState)
{
    return view;
}

public OutdoorResetView getView()
{
    return view;
}
}
Mark Herscher
  • 1,761
  • 2
  • 19
  • 32