旋转导航抽屉时片段变化

4

当前情况

我的应用程序中有一个带有片段的导航抽屉。在纵向模式下一切正常。

问题

假设我在纵向模式下从导航抽屉中选择第二个项目。它可以完美地加载,但是当我将手机旋转到横向模式时,导航菜单中的第一个片段会被加载而不是第二个片段。

我知道我必须保存片段实例,但我不知道如何做,我应该在主活动中还是在片段本身中进行保存?

5个回答

3

我在这个帖子中回答了同样的问题:

如何在导航抽屉活动中由于方向更改而重新启动时保留相同的片段

我试图解释为什么我提供的解决方案有效,所以如果你感兴趣就去看看吧。

为了解决这个问题,我只需将膨胀初始片段的代码放在一个if语句中(在导航抽屉活动的OnCreate中):

super.onCreate(savedInstanceState);
if(savedInstanceState==null){
    FragmentManager fM = getSupportFragmentManager();
    fM.beginTransaction().replace(R.id.NavDrawContent,new home_fragment()).commit();
}

所以当我们在第二个片段中改变方向时,它不会使第一个片段膨胀。

3

我已经在onActivityCreated中使用了setRetainState。还需要什么?? - Vivek Mishra
请查看此链接:https://dev59.com/pGgu5IYBdhLWcg3wpYcj - ʍѳђઽ૯ท
2
谢谢您提供链接,我进行了一些修改后成功让我的代码运行了。我在主活动中传递了硬编码的整数到显示片段方法中。因此,在保存实例状态时,我只保存了位置,然后在onCreate中加载该位置的片段。 - Vivek Mishra

1
我发现使用名为ViewModel的新工具可以找到更好的解决方案。当屏幕旋转时,它会自动销毁活动并重新创建,因此我们失去了上一个选择的片段的焦点。ViewModel帮助我们保持数据,并且对于表单也非常有用。
1. 创建一个名为MainActivityViewModel.kt的类。 2. 将以下代码放入其中: class MainActivityViewModel:ViewModel(){ var menuItem:Int = R.id.nav_inicio }
我将R.id.nav_inicio作为默认菜单项,根据您的activity_main_drawer.xml(Android Studio的默认名称)进行修改。
3. 然后,在具有导航抽屉的MainActivity中声明它: lateinit var vm:MainActivityViewModel
  1. 将以下代码添加到onCreate方法中:

    vm = ViewModelProviders.of(this).get(MainActivityViewModel::class.java)

  2. 然后创建一个函数来加载默认的Fragment:

    fun loadDefaultFragment() { when (vm.menuItem) { R.id.nav_inicio -> { fab.hide() val fragment = InicioFragment() val manager = supportFragmentManager manager.beginTransaction().replace(R.id.content_main, fragment, fragment.getTag()).commit() } R.id.nav_puntosventa -> { fab.show() val fragment = ListaPuntosFragment() val manager = supportFragmentManager manager.beginTransaction().replace(R.id.content_main, fragment, fragment.getTag()).commit() } else -> { // 如果需要,可以设置默认片段 } } }

这个函数必须在ViewModel初始化后调用,且必须在onCreate方法中调用。

6. 最后,我们必须每次选择一个新的菜单项时更新viewModel的值,因此需要修改onNavigationItemSelected覆盖函数并将其添加到开头:

override fun onNavigationItemSelected(item: MenuItem): Boolean { // 在此处理导航视图项点击事件。 vm.menuItem = item.itemId // 其余代码 ... }

现在,当您旋转屏幕时,viewModel值会保存位置,您可以在表单中使用它。


1

更改配置后,导航控制器返回栈存在问题。

在带有片段的活动中:尝试在更改配置之前保存导航控制器状态。更改配置后,将其重新添加到导航控制器中。例如:

override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putBundle("nav_state", fragment.findNavController().saveState())}

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
fragment.findNavController().restoreState(savedInstanceState.getBundle("nav_state"))}

那是我的情况。

0
新的Android架构组件引入了ViewModel类,它有助于创建生命周期感知组件。它解决了大多数与生命周期管理相关的问题。如果您在项目中使用Java代码,可以引入ViewModel类。按照以下步骤操作:
  1. 将以下代码添加到您的build.gradle(app module)文件中

    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    
  2. 将以下代码添加到您的build.gradle(project module)文件中

    dependencies {
    
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"
    }
    
  3. 创建一个名为MainActivityViewModel.kt的新类,并使用以下代码

    class MainActivityViewModel : ViewModel() {
    var menuItem: Int = R.id.nav_home
    }
    
  4. 在您的MainActivity.java文件中,在类的顶部添加以下代码

    private MainActivityViewModel vm;
    

    并在MainActivity.java onCreate方法中添加以下代码

    vm = new ViewModelProvider(this).get(MainActivityViewModel.class);
    loadDefaultFragment();
    
  5. 现在,在您的MainActivity.java文件中创建一个名为loadFragment()的方法,并使用以下代码

    private void loadFragment(Fragment fragment) {
    // 加载fragment
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.contentMainLayout, fragment);
    transaction.addToBackStack(null);
    transaction.commit();
    }
    
  6. 在您的MainActivity.java文件中创建另一个名为loadDefaultFragment()的方法,并使用以下代码

    private void loadDefaultFragment(){
    if(vm.getMenuItem()==R.id.nav_home){
        fragment = new HomeFragment();
        loadFragment(fragment);
    }else if(vm.getMenuItem()==R.id.nav_another_fragment){
        fragment = new AnotherFragment();
        loadFragment(fragment);
    }
    // 根据您的需求添加或排除其他fragment
    }
    
  7. 最后,每次选择新菜单项时,我们都必须更新viewModel值,因此在onNavigationItemSelected方法的开头进行修改:

    // 在此处理导航视图项单击。
    vm.setMenuItem(item.getItemId());
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接