首页 > 解决方案 > java.lang.IllegalStateException:当我有一个 BottomNavigationBar 时已经添加了片段 - 可能是片段的多个实例

问题描述

这很复杂,但是我的应用程序中有一个部分(“运行”部分),它的底部导航栏有 4 个图标/片段。当我第一次“运行”时,一切正常。当我第二次“运行”时,只要单击导航栏主/默认(或第一个)片段中列出的回收视图中的一个项目,应用程序就会崩溃。我收到的错误是:

java.lang.IllegalStateException: Fragment already added

我认为其中一个复杂性是应用程序的“运行”部分是一个片段,其中包含 BottomNavigationView。所有的例子似乎在活动中都有这个。

我已经读过这可能是一个一般性错误,但我确实注意到在主/默认片段中单击 recyclerview 项目时出现的日志消息似乎从重复出现,就好像有多个实例一样:

第一次运行:

2021-07-29 07:51:37.996  D/RunScenarioFragment: showDialog: dialog is null
2021-07-29 07:51:37.996  D/RunScenarioFragment: showDialog: creating new dialog

第二次运行:

2021-07-29 07:53:04.565  D/RunScenarioFragment: showDialog: dialog is null
2021-07-29 07:53:04.565  D/RunScenarioFragment: showDialog: creating new dialog
2021-07-29 07:53:04.575  D/RunScenarioFragment: showDialog: dialog is NOT null
2021-07-29 07:53:04.575  D/RunScenarioFragment: showDialog: no need to create new dialog.
2021-07-29 07:53:04.580  D/RunScenarioFragment: showDialog: dialog is NOT null
2021-07-29 07:53:04.580  D/RunScenarioFragment: showDialog: no need to create new dialog.

底部导航栏中的代码如下,根据so中的其他示例,这似乎是合理的:

private void switchFragment(Fragment fragment) {
    FragmentManager fm = getActivity().getSupportFragmentManager();
    fm.beginTransaction().replace(R.id.frame_layout_run_scenario, fragment).addToBackStack(null).commit();
}

是否正在创建同一片段的多个实例?我不知道这怎么可能发生。我想它一定是在我创建带有 BottomNavigationBar 的片段时,但这实际上只是一个导航调用。也许当我退出但我再次导航离开:

navController.navigate(R.id.action_global_scenarioListFragment2);

这是我的听众:

bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {

            Fragment selectedFragment;

            switch (menuItem.getItemId()) {
                case R.id.runScenarioDashboardFragment:   //nav_scenario_run_home
                    selectedFragment = new RunScenarioDashboardFragment();
                    break;
                case R.id.runScenarioLogFragment:       //nav_scenario_run_log
                    selectedFragment = new RunScenarioLogFragment();
                    break;
                case R.id.runScenarioCommunicationFragment:     //communication fragment

                    selectedFragment = new RunScenarioCommunicationFragment();
                    break;
                default:
                    selectedFragment = new RunScenarioTokenFragment();
                    break;
            }

            switchFragment(selectedFragment);
            return true;
        }
    });

更新 它似乎与我正在调用的自定义 AppCompatDialogFragment 有关。

我用于底部导航的代码工作正常。不是这部分代码导致了问题。这是 AppCompatDialogFragment 被多次调用。

我的错。感谢您的帮助。

标签: javaandroidandroid-fragments

解决方案


在您的片段类中声明片段如下

RunScenarioDashboardFragment runScenarioDashboardFragment;
RunScenarioLogFragment runScenarioLogFragment;
RunScenarioCommunicationFragment runScenarioCommunicationFragment;
RunScenarioTokenFragment runScenarioTokenFragment

@Override
    public void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        runScenarioDashboardFragment = new RunScenarioDashboardFragment();
        runScenarioLogFragment = new RunScenarioLogFragment();
        runScenarioCommunicationFragment = new RunScenarioCommunicationFragment();
        runScenarioTokenFragment = new RunScenarioTokenFragment();

    }

@Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        // your onCreateView implementation
    }

将您的导航侦听器更新为

bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
        Fragment selectedFragment=null;

        switch (menuItem.getItemId()) {
            case R.id.runScenarioDashboardFragment:   //nav_scenario_run_home
                selectedFragment = runScenarioDashboardFragment;
                break;
            case R.id.runScenarioLogFragment:       //nav_scenario_run_log
                selectedFragment = runScenarioLogFragment;
                break;
            case R.id.runScenarioCommunicationFragment:     //communication fragment

                selectedFragment = runScenarioCommunicationFragment;
                break;
            default:
                selectedFragment = runScenarioTokenFragment;
                break;
        }

        switchFragment(selectedFragment);
        return true;
    }
});

还要更新你的 switchFragment()

private void switchFragment(Fragment fragment) {
    FragmentManager fm = getActivity().getSupportFragmentManager();
    
    // this will popout the fragment in back stack if it was there and then 
    // begin the new transaction, add following code only if you add fragment to back stack
    if(getSupportFragmentManager().getBackStackEntryCount()>0)
        getSupportFragmentManager()..popBackStack();

    fm.beginTransaction().replace(R.id.frame_layout_run_scenario, fragment).addToBackStack(null).commit();
}

或者只是不添加到后台堆栈中

fm.beginTransaction().replace(R.id.frame_layout_run_scenario,    fragment).commit();

推荐阅读