java—如何在不破坏和重新创建片段的情况下在片段之间切换(以类似静电的方式)

ufj5ltwl  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(393)

我的应用程序使用bottomnavigationbar在片段之间切换,它是这样做的:

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 . 事先谢谢:)

vbkedwbf

vbkedwbf1#

replace() 意味着销毁这个,并在其位置添加新的,因为你的代码是现在你不能使用 add() 或者是因为根据这个switch case,您将在每次导航时创建一个新的片段示例。它会浪费内存,最终应用程序会崩溃 OutOfMemoryException 你能做什么?
不幸的是,使用底部导航没有太多的选项,但是您可以使用以下选项进行改进
1使用 viewmodels 为每个碎片和附加所有 viewmodels 通过这样的主机活动,您不必每次创建片段时都加载数据,数据将保留在viewmodels中
2或使用viewpager保存片段viewpager将能够在内存中保存所有片段并查看所需片段,通过调用 setCurrentItem() 在viewpager上 OnNavigationItemSelected() 3使用 add() 而不是 replace() 并使您的片段是单例的,这样您就不会每次都加载数据(如果您不使用视图模型),现在还可以跟踪最后一个片段,如果用户转到另一个片段,并且在转到其他任何地方之前返回到这个片段,您只需使用 getSupportFragmantManager().popBackStack() 若要移除此片段堆栈,请弹出后堆栈并添加另一个片段
4使用其他形式的导航—请参阅导航组件,让您的生活更轻松
也许有更好的解决方案,但这是我所能想到的根据我的经验,这不是很多,虽然导航组件也做替换的事情,我不认为这是很坏的,如果你使用视图模型来保存数据。
快乐编码

m2xkgtsf

m2xkgtsf2#

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

首先,所有片段都声明为内部的字段 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;

                }
            };

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

相关问题