如何在 Fragment 之间切换而不破坏它们?

问题描述 投票:0回答:3

我正在玩原生 Android 应用程序导航,使用 BottomNavigationBar 在 Fragments 之间切换:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
    }

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

                    switch (item.getItemId()) {
                        case R.id.first:
                            selectedFragment = new FirstFragment();
                            break;
                        case R.id.second:
                            selectedFragment = new SecondFragment();
                            break;
                        case R.id.third:
                            selectedFragment = new ThirdFragment();
                            break;
                    }

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

                    return true;

                }
            };
}

我希望这些

Fragments
在导航之间持续存在。有什么建议吗?

java android android-studio android-fragments android-menu
3个回答
4
投票

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

  • 首先,所有的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();
    }
  • 最后,在
    MainActivity
    OnCreate()
    方法中以这种方式定义任何菜单的侦听器:
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;

                }
            };

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


2
投票

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

你能做什么?

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

1 为每个片段使用

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

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

setCurrentItem()
 在 viewpager 上调用 OnNavigationItemSelected()

3使用

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

4 使用其他形式的导航请参阅导航组件让您的生活变得更轻松

也许有更好的解决方案,但这就是我根据我的经验所能想到的,虽然导航组件也可以做替换的事情,但我认为如果你使用视图模型来保存数据,这并不是很糟糕.

快乐编码


0
投票

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

显示片段 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();

© www.soinside.com 2019 - 2024. All rights reserved.