0

I have been trying to get my android app to be able to that when you switch between fragments it retains the actions you've done in the fragments. I want to be able to switch between fragments without re-creating or replacing them, just showing and hiding them. Such as if you checked a box in fragment 1 but switch to fragment 2 then back to fragment 1, the box should still be checked. I tried implementing the solution outlined in this post from @Tester101 How can I switch between two fragments, without recreating the fragments each time?

But I'm not sure if I'm getting it to work properly. When I switch to the WidgetFragment from the HomeFragment, the WidgetFragment gets placed on top of the HomeFragment.

The HomeFragment looks like this: Text But when I switch to the WidgetFragment it looks like this: Text With the textview and the checkbox from the WidgetFragment getting placed on top of the HomeFragment.

package loon.si.weather_app;

import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.FragmentManager;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.MenuItem;

import com.google.android.material.navigation.NavigationView;

import java.util.Objects;

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
    
    private DrawerLayout drawerLayout;

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

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        
        drawerLayout = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);

        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open_nav, R.string.close_nav);

        drawerLayout.addDrawerListener(toggle);
        toggle.syncState();

        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragment_container, new HomeFragment()).commit();
            navigationView.setCheckedItem(R.id.nav_home);
        }

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        FragmentManager fragmentManager = getSupportFragmentManager();
        if(fragmentManager.findFragmentById(R.id.nav_home) != null){
            fragmentManager.beginTransaction().remove(Objects.requireNonNull(fragmentManager.findFragmentById(R.id.nav_home))).commit();
        }
        if(fragmentManager.findFragmentById(R.id.nav_widget) != null){
            fragmentManager.beginTransaction().remove(Objects.requireNonNull(fragmentManager.findFragmentById(R.id.nav_widget))).commit();
        }
    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        switch (item.getItemId()){
            case R.id.nav_home:
                if(fragmentManager.findFragmentById(R.id.nav_home) != null) {
                    //if the fragment exists, show it.
                    fragmentManager.beginTransaction().show(Objects.requireNonNull(fragmentManager.findFragmentById(R.id.nav_home))).commit();
                } else {
                    //if the fragment does not exist, add it to fragment manager.
                    fragmentManager.beginTransaction().add(R.id.fragment_container, new HomeFragment(), "home").commit();
                }
                if(fragmentManager.findFragmentById(R.id.nav_widget) != null){
                    //if the other fragment is visible, hide it.
                    fragmentManager.beginTransaction().hide(Objects.requireNonNull(fragmentManager.findFragmentById(R.id.nav_widget))).commit();
                }
                break;

            case R.id.nav_widget:
                if(fragmentManager.findFragmentById(R.id.nav_widget) != null) {
                    //if the fragment exists, show it.
                    fragmentManager.beginTransaction().show(Objects.requireNonNull(fragmentManager.findFragmentById(R.id.nav_widget))).commit();
                } else {
                    //if the fragment does not exist, add it to fragment manager.
                    fragmentManager.beginTransaction().add(R.id.fragment_container, new WidgetFragment(), "widget").commit();
                }
                if(fragmentManager.findFragmentById(R.id.nav_home) != null){
                    //if the other fragment is visible, hide it.
                    fragmentManager.beginTransaction().hide(Objects.requireNonNull(fragmentManager.findFragmentById(R.id.nav_home))).commit();
                }
                break;
        }
        drawerLayout.closeDrawer(GravityCompat.START);
        return true;
    }

    @Override
    public void onBackPressed() {
        if (drawerLayout.isDrawerOpen(GravityCompat.START)){
            drawerLayout.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }
}
johndo19
  • 13
  • 3
  • "Such as if you checked a box in fragment 1 but switch to fragment 2 then back to fragment 1, the box should still be checked." - if you are [saving your fragment's state](https://developer.android.com/guide/fragments/saving-state), that is already the case. Saving your state correctly is already required for handling screen rotations and other configuration changes as well as for handling process death and recreation. You aren't actually saving yourself any work going through this manual show/hide work. – ianhanniballake Mar 21 '23 at 21:40

1 Answers1

1

To retain the state of fragments when switching between them, you need to use the addToBackStack method of the FragmentTransaction class. This method adds the current fragment to the back stack, which allows the user to navigate back to the previous fragment by pressing the back button.

transaction.addToBackStack(null).commit();
drawerLayout.closeDrawer(GravityCompat.START);

Use the findFragmentByTag method to find the fragment by its tag name instead of its ID, as the tag name is unique and doesn't change when the fragment is hidden or shown.

if(fragmentManager.findFragmentByTag("home") != null) {
    transaction.show(Objects.requireNonNull(fragmentManager.findFragmentByTag("home")));
} 
else {
    transaction.add(R.id.fragment_container, new HomeFragment(), "home");
}
if(fragmentManager.findFragmentByTag("widget") != null){
    transaction.hide(Objects.requireNonNull(fragmentManager.findFragmentByTag("widget")));
}
break;
Fluffeh
  • 33,228
  • 16
  • 67
  • 80
Sana Momin
  • 43
  • 5
  • if(fragmentManager.findFragmentByTag("home") != null) { transaction.show(Objects.requireNonNull(fragmentManager.findFragmentByTag("home"))); } else { transaction.add(R.id.fragment_container, new HomeFragment(), "home"); } if(fragmentManager.findFragmentByTag("widget") != null){transaction.hide(Objects.requireNonNull(fragmentManager.findFragmentByTag("widget"))); } – Sana Momin Mar 22 '23 at 10:18
  • if(fragmentManager.findFragmentByTag("widget") != null) { transaction.show(Objects.requireNonNull(fragmentManager.findFragmentByTag("widget"))); } else { transaction.add(R.id.fragment_container, new WidgetFragment(), "widget"); } if(fragmentManager.findFragmentByTag("home") != null) { transaction.hide(Objects.requireNonNull(fragmentManager.findFragmentByTag("home"))); } break; – Sana Momin Mar 22 '23 at 10:23