Search code examples
javascriptandroid-studioandroid-fragmentsandroid-activitybottom-sheet

App crashes when trying to initiate fragment on bottomSheet


The problem may be coming from my architecture but I'm not too sure.

Here's the problem.

I have an activity which initiate a fragment. The .xml file of that activity contains, a FrameLayout for the fragment (let's call it FragmentA) and a CoordinatorLayout which acts as a bottomSheet.

Inside the bottomSheet, there's another FrameLayout for an another fragment (let's call it FragmentB).

What I'm trying to accomplish is that when the bottomSheet is expanded all the way, then, on its FrameLayout, I initiate FragmentB.

To save space, I decided to handle everything related to the bottomSheet in a different, separate class, named BottomSheetManagement

I, then, attached BottomSheetCallback on my bottomSheet and when its state is expanded, I call the method initiateFragment(currentFragmentID, WorkFragment.newInstance()).

This method is created in an interface called FragmentHost which is implemented in my mainActivity. Thus, when I call initiateFragment(currentFragmentID, WorkFragment.newInstance()), I'm actually calling the method of the same name in my mainActivity.

However, when I test my app and drag my bottomSheet to the top, i get the error message : IllegalStateException : Activity has been destroyed.

I don't understand how since in initiateFragment(currentFragmentID, WorkFragment.newInstance()), I make sure that the activity is still there (through !isfinishing() && !isDestroyed())

What can I do?

MainActivity.java

public class MainActivity extends AppCompatActivity implements FragmentHost {

    //BottomSheet Variables
    View bottomSheet;
    RelativeLayout bottomSheetHeader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.container, MainFragment.newInstance())
                    .commitNow();
        }
        //Handle BottomSheet
        bottomSheet = findViewById(R.id.bottom_sheet);
        bottomSheetHeader = findViewById(R.id.BottomSheet_Layout_Header);
        bottomSheetManagement();
    }
    private void bottomSheetManagement(){
        BottomSheetManagement bottomSheetManagement = new BottomSheetManagement();
        bottomSheetManagement.handleBottomSheet(R.id.work_container, bottomSheet, bottomSheetHeader);
    }

    @Override
    public void initiateFragment(int containerID, Fragment fragment) {
        if (!isFinishing() && !isDestroyed()){
            getSupportFragmentManager().beginTransaction()
                    .replace(containerID, fragment)
                    .commit();
        }
    }
}

BottomSheetManagement.java

public class BottomSheetManagement {
    private BottomSheetBehavior bottomSheetBehavior;
    private int activeBottomSheetState;

    public void handleBottomSheet(int currentFragmentID, View bottomSheet, RelativeLayout bottomSheetHeader){
        FragmentHost fragmentHost = new MainActivity();
        bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
        bottomSheetHeader.setOnClickListener(v -> {
            switch (bottomSheetBehavior.getState()){
                case BottomSheetBehavior.STATE_COLLAPSED:
                    bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                    break;
                case BottomSheetBehavior.STATE_EXPANDED:
                    bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                    break;
            }
        });
        bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
                switch (newState){
                    case BottomSheetBehavior.STATE_EXPANDED:
                        fragmentHost.initiateFragment(currentFragmentID, WorkFragment.newInstance());
                        break;
                }
            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {

            }
        });
    }
}

main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:id="@+id/bottom_sheet"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="?attr/colorSurface"
            app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
            app:behavior_hideable="false"
            app:behavior_peekHeight="50dp"
            android:orientation="vertical">
            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="?android:attr/listDivider" />
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="16dp"
                android:id="@+id/BottomSheet_Layout_Header">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:text="@string/app_name"
                    style="?attr/titleTextAppearance"
                    android:textColor="?attr/colorOnSurface"/>
            </RelativeLayout>

            <FrameLayout
                android:id="@+id/work_container"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

        </LinearLayout>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout>

Solution

  • You should assign the context of MainActivity already created to fragmentHost instead of creating a new context which you are doing by writing 'new MainActivivty()' which destroys previous MainActivity from where you called BottomSheetManagement and creates a new one. Modify your BottomSheetManagement code to,

    public class BottomSheetManagement {
        private BottomSheetBehavior bottomSheetBehavior;
        private int activeBottomSheetState;
        private FragmentHost fragmentHost;
    
        public void handleBottomSheet(FragmentHost context, int currentFragmentID, View bottomSheet, RelativeLayout bottomSheetHeader){
            fragmentHost = (FragmentHost) context;
            bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
            bottomSheetHeader.setOnClickListener(v -> {
    

    and in MainActivity code, change method to

    private void bottomSheetManagement(){
            BottomSheetManagement bottomSheetManagement = new BottomSheetManagement();
            bottomSheetManagement.handleBottomSheet(this, R.id.work_container, bottomSheet, bottomSheetHeader);
        }