Naveed
Naveed

Reputation: 3202

How to save and reuse same instance of fragments?

I have recently started using fragments have created a demo app which looks like this:

Demo App

Clicking on each button switches between fragment 1, Fragment 2, and Fragment 3.

What I am trying to accomplish is to only have 1 instance of each Fragment and reuse that. (Please note that all the fragments are created and added dynamically). Currently I am doing this by creating a HashMap of fragment and placing each instance and grabbing it from there.

So my questions are: Is there a better way of doing this: By using FragmentManager's putFragment(...) method? putFragment (Bundle bundle, String key, Fragment fragment) I can't figure out how to use it in my case. If anyone can give me an example of how to use this method.

Is it expensive to hold onto a reference of each fragment in my activity? Does this keep all the fragments alive? I am using soft reference to tackle this but I am not sure if this is the proper way of doing this. Please point me towards any alternative way of doing this or let me know if this is best way to accomplish this.

Thanks in advance.

Here is my code:

UPDATE: I am trying to reuse fragments from the back stack, trying to only add them if it does not exists in the back stack. The code below gives me the Illegal state exception after I navigate away from fragment one -> come back to it -> then try to press back button:

10-28 13:21:40.255: ERROR/MessageQueue-JNI(3548): java.lang.IllegalStateException: Fragment already added: FragmentOne{423db570 #0 id=0x7f050006 fragOne}

public class MainActivity extends Activity implements View.OnClickListener {

private Button btnOne;
private Button btnTwo;
private Button btnThree;

 /* Called when the activity is first created.
  */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    initialize();
    if(findViewById(R.id.fl) != null){
        if(savedInstanceState != null)
            return;
    }

    FragmentManager.enableDebugLogging(true);
    updateView("fragOne");
}

private void initialize(){
    btnOne = (Button) findViewById(R.id.button1);
    btnTwo = (Button) findViewById(R.id.button2);
    btnThree = (Button) findViewById(R.id.button3);
    btnOne.setOnClickListener(this);
    btnTwo.setOnClickListener(this);
    btnThree.setOnClickListener(this);
    fragHolder = new HashMap<String, SoftReference<Fragment>>();
}

private void updateView(String tag){
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment frag = getFragmentManager().findFragmentByTag(tag);

    boolean addToStack = true;
    if(frag == null){
        if(tag.equals("fragOne"))
            frag = new FragmentOne();    
        else if(tag.equals("fragTwo"))
            frag = new FragmentTwo();
        else if(tag.equals("fragThree"))
            frag = new FragmentThree();
    }else{
        //Don't add to back stack
        addToStack = false;
    }
    ft.replace(R.id.fl, frag, tag);
    if(addToStack)
        ft.addToBackStack(null);
    ft.commit();
}

    @Override
    public void onClick(View v) {
        switch(v.getId()){
            case R.id.button1:
                updateView("fragOne");
                break;
            case R.id.button2:
                updateView("fragTwo");
                break;
            case R.id.button3:
                updateView("fragThree");
                break;
        }
    }
}

Upvotes: 15

Views: 18839

Answers (2)

znat
znat

Reputation: 13474

The FragmentManager does it's own memory management. It will kill/recreate or keep in memory your instances according to its logic. You can ensure your fragment's state is save using onSaveInstanceState()

Or you can for force the system to keep your instance alive using setRetainInstance(true) on your Fragment.

This is how you create a transaction.

    FragmentTransaction fragmentTransaction = context.getSupportFragmentManager().beginTransaction();
    fragmentTransaction.replace(R.id.layout, new MyFragment(), f.getClass().getName());
    fragmentTransaction.commit();

Upvotes: 1

Andrew Schuster
Andrew Schuster

Reputation: 3229

To demonstrate a FragmentTransaction, the following sample might be helpful to you.

First, you want to do all your initialization stuff in the onCreate() of your activity, which you have right, but we'll make a few changes.

public class MainActivity extends Activity implements View.OnClickListener {

private Button btnOne;
private Button btnTwo;
private Button btnThree;

/* Called when the activity is first created.*/
@Override
public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    initialize();
    if(findViewById(R.id.fl) != null)
    {
        if(savedInstanceState != null)
        {
            FragmentTransaction trans = getFragmentManager().beginTransaction();

            //This is where we add our first fragment
            trans.add(R.id.fl, new FragmentOne());
            trans.commit();
        }
    }
}

private void initialize()
{
    btnOne = (Button) findViewById(R.id.button1);
    btnTwo = (Button) findViewById(R.id.button2);
    btnThree = (Button) findViewById(R.id.button3);
    btnOne.setOnClickListener(this);
    btnTwo.setOnClickListener(this);
    btnThree.setOnClickListener(this);
}

public void onClick(View view)
{
    //Here is where we'll actually transfer the fragments

    FragmentTransaction trans = getFragmentManager().beginTransaction();
    switch(v.getId()){
        case R.id.button1:
            trans.replace(R.id.fl, new FragmentOne());
            trans.addToBackStack(null);
            trans.commit();
            break;
        case R.id.button2:
            trans.replace(R.id.fl, new FragmentTwo());
            trans.addToBackStack(null);
            trans.commit();
            break;
        case R.id.button3:
            trans.replace(R.id.fl, new FragmentThree());
            trans.addToBackStack(null);
            trans.commit();
            break;
    }
}

This will allow you to easily transition from one Fragment to the next.

Upvotes: 2

Related Questions