Skip to content
Advertisement

How can I switch between Fragments without destroying and re-creating them? (in a static-like way)

My app uses a BottomNavigationBar to switch between Fragments, and it does it this way:

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        BottomNavigationView bottomNav = findViewById(R.id.barra);
        bottomNav.setOnNavigationItemSelectedListener(navListener);

        getSupportFragmentManager().beginTransaction().replace(R.id.container, new KeyboardFragment()).commit();
        bottomNav.setSelectedItemId(R.id.keyboard);

    }


    private BottomNavigationView.OnNavigationItemSelectedListener navListener =
            new BottomNavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                    Fragment selectedFragment = null;

                    switch (item.getItemId()){
                        case R.id.camera:
                            selectedFragment = new CameraFragment();
                            break;
                        case R.id.keyboard:
                            selectedFragment = new KeyboardFragment();
                            break;
                        case R.id.settings:
                            selectedFragment = new SettingsFragment();
                            break;
                    }

                    getSupportFragmentManager().beginTransaction().replace(R.id.container,
                            selectedFragment).commit();

                    return true;

                }
            };
}

I want those Fragments to be static, so their content and views do not dissapear when I switch between them. I have tried to create them inside MainActivity‘s onCreate() method, but it only helps with retaining text inside EditText widgets, the rest of the views and content dissapear.

I have seen other similar questions, but they are answered poorly and I am new to this. Following some answers to similar questions, I have tried to use functions like add() or attach() instead of replace() but I don’t think I’m doing it well; in fact sometimes my app crashes.

Should I paste here my layout.xml files too? The fragments are “displayed” into a simple FrameLayout. Thanks beforehand 🙂

Advertisement

Answer

This is how I solved the problem succesfully:

  • First of all, all of the Fragments are declared as fields inside MainActivity class, as well as the variable selected, which will be used later:
public class MainActivity extends AppCompatActivity {

    public KeyboardFragment keyboard_fragment = new KeyboardFragment();
    public CameraFragment camera_fragment = new CameraFragment();
    public SettingsFragment settings_fragment = new SettingsFragment();
    
    Fragment selected = teclado_fragment;`

    //...
  • Then, the following methods are defined inside the class too, where R.id.container is the FrameLayout or whatever view that is being used to display the inflated Fragments:
    private void createFragment(Fragment fragment){
                 getSupportFragmentManager().beginTransaction()
                .add(R.id.container, fragment)
                .hide(fragment)
                .commit();
    }
    private void showFragment(Fragment fragment){
                 getSupportFragmentManager().beginTransaction()
                .show(fragment)
                .commit();
    }
    private void hideFragment(Fragment fragment){
                 getSupportFragmentManager().beginTransaction()
                .hide(fragment)
                .commit();
    }
  • Finally, whatever menu’s listener is defined this way inside MainActivity‘s OnCreate() method:
private BottomNavigationView.OnNavigationItemSelectedListener navListener =
            new BottomNavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem item) {

                    switch (item.getItemId()){
                        case R.id.camera:
                            hideFragment(selected);
                            selected = camera_fragment;
                            showFragment(seleccionado);
                            break;
                        case R.id.keyboard:
                            hideFragment(selected);
                            selected = keyboard_fragment;
                            showFragment(seleccionado);
                            break;
                        case R.id.settings:
                            hideFragment(selected);
                            selected = settings_fragment;
                            showFragment(seleccionado);
                            break;
                    }

                    return true;

                }
            };

This way, the menu just hides and shows Fragments visually, and they are only declared once not to be destroyed until the app closes, thus mantaining all their fields and views in memory as long as the app is running.

Advertisement