How to keep only one instance of a fragment, when

2019-01-23 08:25发布

问题:

My App starts with a AddressFragment. From the NavigationDrawer I start (amongst others) a new AddressFragment with:

getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, new AddressFragment())
                .addToBackStack(null)
                .commit();

But I would rather just go back the first instance. How could I do that?

Or more general, how can I find out, whether an instance of a fragment already exists and then start that, if yes, otherwise create one?

回答1:

When creating the fragment set a tag for it, then later you can find it through the fragment manager and replace/create accordingly.

FragmentManager fManager = getFragmentManager();
FragmentTransaction fTransaction = fManager.beginTransaction();
Fragment fragment = fManager.findFragmentByTag("uniqueTag");

// If fragment doesn't exist yet, create one
if (fragment == null) {
    fTransaction.add(R.id.fragment_list, new ListFrag(), "uniqueTag");
}
else { // re-use the old fragment
    fTransaction.replace(R.id.fragment_list, fragment, "uniqueTag");
}


回答2:

Step one:

Optimize current code to allow a Fragment to have his own "TAG"

getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, new AddressFragment())
                .addToBackStack(**AddressFragment.class.getName()**)
                .commit();

Step two:

Somewhere in your application flow you will need to determine if a fragment exists:

public static boolean isFragmentInBackstack(final FragmentManager fragmentManager, final String fragmentTagName) {
    for (int entry = 0; entry < fragmentManager.getBackStackEntryCount(); entry++) {
        if (fragmentTagName.equals(fragmentManager.getBackStackEntryAt(entry).getName())) {
            return true;
        }
    }
    return false;
}

Step three:

perform fragment action

if (exists) {
    // Fragment exists, go back to that fragment
    //// you can also use POP_BACK_STACK_INCLUSIVE flag, depending on flow
    mFragmentManager.popBackStackImmediate(AddressFragment.class.getName(), 0);

} else {
    // Fragment doesn't exist
    // STEP 1 + additional backstack management
}


回答3:

First time you create the fragment with a tag.

When you want to replace it try to get the fragment with tag and if it return null you create a new one



回答4:

This is tested answer, Hope this will help you First Make these field globally in MainActivity

private static final int TIME_INTERVAL = 2000; 
private long mBackPressed;
private FragmentManager fm;
private FragmentTransaction ft;
private DrawerLayout drawer;

Now in onNavigationItemSelected() implement like that

    @Override
public boolean onNavigationItemSelected(MenuItem item) {
Fragment fragment = null;
Class fragmentClass = null;
switch (item.getItemId()) {
case R.id.nav_home:
fragmentClass = Fragment.class;//this is MainAvctivty extends AppCompatActivity
break;
case R.id.nav_f1:
fragmentClass = FragmentOne.class;
break;
case R.id.nav_f2:
fragmentClass = FragmentTwo.class;
break;
case R.id.nav_f3:
fragmentClass = FragmentThree.class;
break;
case R.id.nav_f4:
fragmentClass = FragmentFour.class;
break;
case R.id.nav_f5:
fragmentClass = FragmentFive.class;
break;
default:
fragmentClass = Fragment.class;
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {e.printStackTrace();}
//Insert the fragment by replacing any existing fragment
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
ft.replace(R.id.frame_container, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
item.setChecked(true);
setTitle(item.getTitle());
drawer.closeDrawers();
return true;
}

Now handle onbackpressed like below

@Override
public void onBackPressed() {
if (drawer != null) {
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
ft.commit();
} else if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()) {
super.onBackPressed();
} else {
Toast.makeText(this,"Press again to exit the app",Toast.LENGTH_SHORT).show();
}
mBackPressed = System.currentTimeMillis();
}
}