IllegalStateException:使用BottomNavigation

时间:2018-09-12 19:34:30

标签: android android-fragments navigation-drawer navigationview

我正在使用the following example中的BottomNavigationDrawer / BottomSheetDialog,其中BottomNavigationDrawer在单个活动中的多个片段之间切换。

implementing the BottomNavigationDrawer期间,我意识到,在不使用菜单的情况下交换片段时,即单击片段中的按钮,this left the menu selection in an inconsistent state.也是在主活动中使用函数来解决触发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引起的,而using getChildFragmentManager不是正确的解决方案,因为我不使用嵌套片段,而是在单个活动中仅使用多个片段

我还尝试在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:   致命异常:主要       流程:com.package.name,PID:28025       java.lang.IllegalStateException:片段尚未附加。           在android.support.v4.app.Fragment.instantiateChildFragmentManager(Fragment.java:2386)           在android.support.v4.app.Fragment.getChildFragmentManager(Fragment.java:842)           在com.package.name.Fragments.BottomNavigationDrawerFragment $ 2.onNavigationItemSelected(BottomNavigationDrawerFragment.java:108)           在android.support.design.widget.NavigationView $ 1.onMenuItemSelected(NavigationView.java:170)           在android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:840)           在android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:158)           在android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:991)           在android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:981)           在android.support.v7.view.menu.MenuBuilder.performIdentifierAction(MenuBuilder.java:977)           在com.package.name.Reviv.resetNavDefault(Reviv.java:644)           在com.package.name.Fragments.FragmentRevivSettingsMain $ 1.onClick(FragmentRevivSettingsMain.java:77)           在android.view.View.performClick(View.java:6303)           在android.view.View $ PerformClick.run(View.java:24828)           在android.os.Handler.handleCallback(Handler.java:789)           在android.os.Handler.dispatchMessage(Handler.java:98)           在android.os.Looper.loop(Looper.java:164)           在android.app.ActivityThread.main(ActivityThread.java:6798)           在java.lang.reflect.Method.invoke(本机方法)           在com.android.internal.os.Zygote $ MethodAndArgsCaller.run(Zygote.java:240)           在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

1 个答案:

答案 0 :(得分:1)

首先像在page中那样在MainActivity中实现按钮单击事件。然后,假设您在MainActivity中拥有BottomNavigationDrawerFragment实例,只需单击该实例即可获取视图,并在单击按钮时通过该视图进行导航菜单的setSelection调用。确保在调用bottomNavDrawerFragment.show(..)之后通过实例获取视图。否则,您将收到NPE错误。