【问题标题】:IllegalStateException: Fragment has not been attached yet when using BottomNavigationIllegalStateException:使用 BottomNavigation 时尚未附加 Fragment
【发布时间】:2018-09-12 19:34:30
【问题描述】:

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

implementing the BottomNavigationDrawer时,我意识到当不使用菜单交换片段时,即通过单击片段中的按钮,this left the menu selection in an inconsistent state.另外,在主活动中使用函数触发@987654332的解决方案@ 导致崩溃。

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)

【问题讨论】:

    标签: android android-fragments navigation-drawer navigationview


    【解决方案1】:

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

    【讨论】:

    • 非常感谢,菲拉特。我尝试了您建议的解决方案,但决定在单击按钮时创建一个新的 BottomNavFragment 实例,并在创建后设置选择。这要粗略得多,但我想我可以将代码拿出来,并在此代码发布后为您提供更全面的解决方案。 (这是一个测试版)。一旦我实施您的解决方案,我将发布更新,希望很快。我接受你的回答,因为我很确定它应该有效。
    • 不客气,希望对您有所帮助。欢迎随时发表评论以提供进一步的更新。
    猜你喜欢
    • 2021-10-01
    • 1970-01-01
    • 2022-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多