Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I prevent a Fragment's onCreateView() from being called?

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?

like image 568
Mark Herscher Avatar asked Jan 14 '14 01:01

Mark Herscher


3 Answers

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 
}
like image 178
Pawan Maheshwari Avatar answered Nov 16 '22 23:11

Pawan Maheshwari


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.

like image 28
NateCron Avatar answered Nov 16 '22 23:11

NateCron


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;
}
}
like image 43
Mark Herscher Avatar answered Nov 17 '22 01:11

Mark Herscher