IllegalStateException:使用 BottomNavigation 时尚未附加片段

IllegalStateException: Fragment has not been attached yet when using BottomNavigation

我正在使用 the following example 中的 BottomNavigationDrawer/BottomSheetDialog,其中 BottomNavigationDrawer 在单个 activity.[=31 中的多个片段之间切换=]

虽然implementing the BottomNavigationDrawer, I realized that when the fragments were swapped without using the menu, i.e. by clicking a button in a fragment, this left the menu selection in an inconsistent state.另外,在主activity中使用函数触发FragmentTransaction的解决方案导致崩溃。

public void resetNavDefault(){
        if(fragment == null) {
            fragment = new BottomNavigationDrawerFragment();
            navigationView = fragment.getNavigationView();
        } else navigationView = fragment.getNavigationView();
        //navigationView.getMenu().getItem(0).setChecked(true);
        Log.d(TAG, "resetNavDefault: setting check");
        MenuItem item = navigationView.getMenu().getItem(0);
        navigationView.getMenu().performIdentifierAction(item.getItemId(), 0);
    }

我意识到这是由于 getSupportFragmentManager 为空引起的 and/or the fragment not being attached, and using getChildFragmentManager 不是正确的解决方案,因为我不使用嵌套片段,只使用单个 activity 中的多个片段。

我还尝试在 the onDetach is overridden to make the childFragmentManager accessible.

中实施此解决方法

This fix prevents the app from crashing with an NPE(由于 if (!isAdded()) return; 条件)但使启动新片段的按钮无响应(该按钮不起作用)。

如何使用 FragmentTransaction 在两个片段之间导航而不导致 NPE,并且不使菜单选择处于不一致状态?

我的BottomNavigationDrawer实现如下:

BottomNavigationDrawer

public class BottomNavigationDrawerFragment extends BottomSheetDialogFragment {

    BottomNavigationDrawerFragment fragment;
    public NavigationView navigationView;
    ImageView close, menu;
    Statuser statuser;
    RevivDatabase database;
    String email, fname, lname;
    TextView txtUsername, txtEmail;

    private static String TAG = "BottomNavDrawerFragment";

    public BottomNavigationDrawerFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view =  inflater.inflate(R.layout.fragment_bottomsheet, container, false);
        txtUsername = view.findViewById(R.id.txtUsername);
        txtEmail = view.findViewById(R.id.txtEmail);
        navigationView = view.findViewById(R.id.navigation_view);
        database = RevivDatabase.getDatabase(getActivity());
        statuser = database.revivDao().getUserDetails();
        fname = statuser.getFname();
        lname = statuser.getLname();
        email = statuser.getEmail();
        txtEmail.setText(email);
        txtUsername.setText(fname+" "+lname);
        setRetainInstance(true);
        close = view.findViewById(R.id.imgClose);
        fragment = this;
        close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                fragment.dismiss();
            }
        });
        navigationView.setItemIconTintList(null);
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
                menuItem.setChecked(true);
                int id = menuItem.getItemId();
                FragmentManager manager;
                try {
                    manager = getActivity().getSupportFragmentManager();
                } catch (NullPointerException e) {
                    if (!isAdded()) return false;
                    manager = getChildFragmentManager();
                    Log.e(TAG, "onNavigationItemSelected: ", e);
                }
                switch (id){
                    case R.id.app_bar_incident:
                        navigationView.getMenu().findItem(id).setChecked(true);
                        manager.beginTransaction().replace(R.id.containerFrameLayout, new FragmentRevivIncidentDashboard()).commit();
                        Toast.makeText(getContext(), "Request Incident", Toast.LENGTH_SHORT).show();
                        fragment.dismiss();
                        break;
                    case R.id.app_bar_housecall:
                        navigationView.getMenu().findItem(id).setChecked(true);
                        manager.beginTransaction().replace(R.id.containerFrameLayout, new FragmentRevivHousecallDashboard()).commit();
                        fragment.dismiss();
                        Toast.makeText(getContext(), "Request Housecall", Toast.LENGTH_SHORT).show();
                        break;
                    case R.id.settings:
                        navigationView.getMenu().findItem(id).setChecked(true);
                        manager.beginTransaction().replace(R.id.containerFrameLayout, new FragmentRevivSettingsMain()).commit();
                        Toast.makeText(getActivity().getApplicationContext(), "Settings", Toast.LENGTH_SHORT).show();
                        fragment.dismiss();
                        break;

                }
                return true;
            }
        });

        return view;
    }

    @Override
    public void onDetach() {
        super.onDetach();

        try {
            Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
            childFragmentManager.setAccessible(true);
            childFragmentManager.set(this, null);

        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public NavigationView getNavigationView() {
        return navigationView;
    }
}

我的错误信息

09-13 00:26:32.996 28025-28025/com.package.name E/AndroidRuntime: FATAL EXCEPTION: main Process: com.package.name, PID: 28025 java.lang.IllegalStateException: Fragment has not been attached yet. at android.support.v4.app.Fragment.instantiateChildFragmentManager(Fragment.java:2386) at android.support.v4.app.Fragment.getChildFragmentManager(Fragment.java:842) at com.package.name.Fragments.BottomNavigationDrawerFragment.onNavigationItemSelected(BottomNavigationDrawerFragment.java:108) at android.support.design.widget.NavigationView.onMenuItemSelected(NavigationView.java:170) at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:840) at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:158) at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:991) at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:981) at android.support.v7.view.menu.MenuBuilder.performIdentifierAction(MenuBuilder.java:977) at com.package.name.Reviv.resetNavDefault(Reviv.java:644) at com.package.name.Fragments.FragmentRevivSettingsMain.onClick(FragmentRevivSettingsMain.java:77) at android.view.View.performClick(View.java:6303) at android.view.View$PerformClick.run(View.java:24828) at android.os.Handler.handleCallback(Handler.java:789) at android.os.Handler.dispatchMessage(Handler.java:98) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6798) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

首先在您的 MainActivity 中实现按钮单击事件,如此 page。然后假设您在 MainActivity 中有 BottomNavigationDrawerFragment 实例,只需通过该实例获取视图并在单击按钮时通过该视图对导航菜单进行 setSelection 调用。确保在 bottomNavDrawerFragment.show(..) 调用后通过实例获取视图。否则你会得到一个 NPE 错误。