【问题标题】:How can I switch between Fragments without destroying and re-creating them? (in a static-like way)如何在不破坏和重新创建片段的情况下在片段之间切换? (以类似静态的方式)
【发布时间】:2021-04-08 15:34:35
【问题描述】:

我的应用程序使用 BottomNavigationBar 在 Fragments 之间切换,它是这样做的:

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        BottomNavigationView bottomNav = findViewById(R.id.barra);
        bottomNav.setOnNavigationItemSelectedListener(navListener);

        getSupportFragmentManager().beginTransaction().replace(R.id.container, new KeyboardFragment()).commit();
        bottomNav.setSelectedItemId(R.id.keyboard);

    }


    private BottomNavigationView.OnNavigationItemSelectedListener navListener =
            new BottomNavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                    Fragment selectedFragment = null;

                    switch (item.getItemId()){
                        case R.id.camera:
                            selectedFragment = new CameraFragment();
                            break;
                        case R.id.keyboard:
                            selectedFragment = new KeyboardFragment();
                            break;
                        case R.id.settings:
                            selectedFragment = new SettingsFragment();
                            break;
                    }

                    getSupportFragmentManager().beginTransaction().replace(R.id.container,
                            selectedFragment).commit();

                    return true;

                }
            };
}

我希望那些Fragments 是静态的,所以当我在它们之间切换时它们的内容和视图不会消失。我试图在MainActivityonCreate() 方法中创建它们,但它只有助于在EditText 小部件中保留文本,其余视图和内容消失。

我见过其他类似的问题,但他们的回答很差,我对此并不陌生。在对类似问题的一些回答之后,我尝试使用 add()attach() 之类的函数而不是 replace() 但我认为我做得不好;事实上,有时我的应用会崩溃。

我也应该在这里粘贴我的 layout.xml 文件吗?这些片段被“显示”成一个简单的FrameLayout先谢谢 :)

【问题讨论】:

  • “所以当我在它们之间切换时它们的内容和视图不会消失”我不太明白,如果你在旧片段的位置放置一个新片段,旧片段会消失
  • 您的代码很好,但我怀疑您想要实现的目标。你能分享更多信息吗?
  • @abhinavchauhan 我希望片段在视觉上消失,但不会破坏类并创建一个新的。
  • @rajendramahato

标签: java android android-studio android-fragments android-menu


【解决方案1】:

replace() 表示销毁这个并在其位置添加新的,因为您的代码现在您不能使用add(),因为根据该开关情况,您每次导航时都会创建一个新的片段实例. 它会浪费内存,最终应用程序会因OutOfMemoryException而崩溃

你能做什么?

不幸的是,底部导航没有太多选项,但您可以使用以下选项进行改进

1 为每个片段使用viewmodels,并将所有viewmodels 附加到主机活动中,这样您就不必在每次创建片段时都加载数据,数据将保留在视图模型

2 或使用 viewpager 来保存您的片段,viewpager 将能够将所有片段保存在内存中并查看所需的片段,以编程方式设置当前片段 通过从OnNavigationItemSelected()调用查看器上的setCurrentItem()

3 使用add() 而不是replace() 并使您的片段单例 这样您就不会每次都加载数据(如果您是不使用视图模型)现在还跟踪最后一个片段,如果用户转到另一个片段并且在去其他任何地方之前返回到这个片段,您只需使用getSupportFragmantManager().popBackStack()弹出返回以删除此片段堆栈,否则弹出返回堆栈并添加另一个片段

4 使用其他形式的导航,请参阅navigation components,让您的生活更轻松

也许有更好的解决方案,但根据我的经验,这就是我能想到的,这不是很多,虽然导航组件也可以替换我不认为如果你使用视图模型来保持它是非常糟糕的数据。

快乐编码

【讨论】:

    【解决方案2】:

    这就是我成功解决问题的方法:

    • 首先,所有的Fragment都声明为MainActivity类内部的字段,还有变量selected,后面会用到:
    public class MainActivity extends AppCompatActivity {
    
        public KeyboardFragment keyboard_fragment = new KeyboardFragment();
        public CameraFragment camera_fragment = new CameraFragment();
        public SettingsFragment settings_fragment = new SettingsFragment();
        
        Fragment selected = teclado_fragment;`
    
        //...
    
    • 然后,在类中也定义了以下方法,其中R.id.container 是 FrameLayout 或用于显示膨胀片段的任何视图:
        private void createFragment(Fragment fragment){
                     getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, fragment)
                    .hide(fragment)
                    .commit();
        }
        private void showFragment(Fragment fragment){
                     getSupportFragmentManager().beginTransaction()
                    .show(fragment)
                    .commit();
        }
        private void hideFragment(Fragment fragment){
                     getSupportFragmentManager().beginTransaction()
                    .hide(fragment)
                    .commit();
        }
    
    • 最后,在MainActivityOnCreate() 方法中以这种方式定义任何菜单的侦听器:
    private BottomNavigationView.OnNavigationItemSelectedListener navListener =
                new BottomNavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    
                        switch (item.getItemId()){
                            case R.id.camera:
                                hideFragment(selected);
                                selected = camera_fragment;
                                showFragment(seleccionado);
                                break;
                            case R.id.keyboard:
                                hideFragment(selected);
                                selected = keyboard_fragment;
                                showFragment(seleccionado);
                                break;
                            case R.id.settings:
                                hideFragment(selected);
                                selected = settings_fragment;
                                showFragment(seleccionado);
                                break;
                        }
    
                        return true;
    
                    }
                };
    

    这样,菜单只是在视觉上隐藏和显示片段,并且它们只被声明一次不会被销毁,直到应用程序关闭,因此只要它们的所有字段和视图都保留在内存中应用程序正在运行。

    【讨论】:

    • 我希望这会有所帮助。感谢@abhinavchauhan,他之前​​的回答帮助我想出了这个解决方案。
    【解决方案3】:

    第一个检查片段是否存在,如果存在则显示片段并隐藏旧片段

    显示片段 fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag(tag)).commit();

    隐藏片段 fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag(HomeFragment.class.getSimpleName())).commit();

    第二个如果不存在添加片段 fragmentManager.beginTransaction().add(R.id.fragment_activity, fragment, tag).commit();

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-18
      • 2021-12-04
      • 2018-02-04
      • 1970-01-01
      • 2011-01-07
      • 2014-05-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多