Search code examples
androidandroid-fragmentsandroid-bottomnavigationview

How to switch existing fragments when the dialog is closed?


The main screen of the app is for bottom navigation.

And there are 3 menus, all of which are fragments.

Pressing the button on one of the fragments opens the dialog fragment window.

And when the dialog is closed, the old fragment should be switched to another new fragment.

I use show() and hide() instead of replace().

MainAcitivity.java

public class MainActivity extends AppCompatActivity {
    BottomNavigationView bottomNav;

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

        bottomNav = findViewById(R.id.bottom_nav);

        bottomNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                FragmentManager fm = getSupportFragmentManager();
                FragmentTransaction transaction = fm.beginTransaction();
                Fragment curFrag = fm.getPrimaryNavigationFragment();
                String tag = String.valueOf(item.getItemId());
                int id = item.getItemId();

                if(curFrag != null) {
                    transaction.hide(curFrag);
                }

                Fragment fragment = fm.findFragmentByTag(tag);
                if(fragment == null) {
                    if(id == R.id.list)
                        fragment = new WorkoutListFragment();
                    transaction.add(R.id.content_layout, fragment);
                }
                else {
                    transaction.show(fragment);
                }

                transaction.setPrimaryNavigationFragment(fragment);
                transaction.setReorderingAllowed(true);
                transaction.commitNow();
                return true;
            }
        });
    }

    // Switch to another fragment when the dialog is closed
    public void onFragmentChanged() {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        String tag = "ABC";

        Fragment currentFragment = fragmentManager.getPrimaryNavigationFragment();
        if (currentFragment != null) {
            fragmentTransaction.hide(currentFragment);
        }

        Fragment fragment = fragmentManager.findFragmentByTag(tag);
        if (fragment == null) {
            fragment = new WriteRoutineFragment();
            fragmentTransaction.add(R.id.container, fragment, tag);
        } else {
            fragmentTransaction.show(fragment);
        }

        fragmentTransaction.setPrimaryNavigationFragment(fragment);
        fragmentTransaction.setReorderingAllowed(true);
        fragmentTransaction.commitNow();
    }
}

DialogFragment.java


    Button startBtn;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_body_part_dialog, null);
        startBtn = view.findViewById(R.id.check);

        startBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { 
                MainActivity activity = (MainActivity) getActivity();
                activity.onFragmentChanged(); // change fragment
                dismiss();

            }
        });

        return view;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        Dialog dialog = super.onCreateDialog(savedInstanceState);
        dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        dialog.setCanceledOnTouchOutside(false);

        return dialog;
    }
}

WriteRoutineFragment.java

public class WriteRoutineFragment extends Fragment {


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_write_routine, container, false);

        return rootView;
    }
}

ERROR

java.lang.IllegalArgumentException: No view found for id 0x7f0a0082 (com.example.writeweight:id/container) for fragment WriteRoutineFragment{f3a9b6 (137e8e27-12af-4e5a-9397-2cbdc80ed980) id=0x7f0a0082 ABC}
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:875)
        at androidx.fragment.app.FragmentManagerImpl.addAddedFragments(FragmentManagerImpl.java:2100)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1874)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1830)
        at androidx.fragment.app.FragmentManagerImpl.execSingleAction(FragmentManagerImpl.java:1696)
        at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:293)
        at com.example.writeweight.activity.MainActivity.onFragmentChanged(MainActivity.java:78)
        at com.example.writeweight.fragment.BodyPartDialogFragment$2.onClick(BodyPartDialogFragment.java:89)
        at android.view.View.performClick(View.java:8160)
        at android.widget.TextView.performClick(TextView.java:16221)
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:992)
        at android.view.View.performClickInternal(View.java:8137)
        at android.view.View.access$3700(View.java:888)
        at android.view.View$PerformClick.run(View.java:30236)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:246)
        at android.app.ActivityThread.main(ActivityThread.java:8506)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
I/Process: Sending signal. PID: 23516 SIG: 9


ADDED

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.MainActivity">

    <FrameLayout
        android:id="@+id/content_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toTopOf="@id/bottom_nav"/>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_nav"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/bottom_nav_menu"/>

</androidx.constraintlayout.widget.ConstraintLayout>

fragment_write_routine.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".fragment.WriteRoutineFragment">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment" />

</FrameLayout>

Solution

  • When you say

    fragmentTransaction.add(R.id.container, fragment, tag);
    

    What you're saying is that you want the FragmentManager to find the R.id.container in your layout and add your fragment to that container. As you're using getSupportFragmentManager(), you're using the Activity's FragmentManager and hence, R.id.container needs to be in your activity's layout. However, R.id.container isn't in your activity's layout, which is why you're getting an exception.

    Instead, you should be using the container that is in your Activity's layout - R.id.content_layout:

    fragmentTransaction.add(R.id.content_layout, fragment, tag);