片段随着导航抽屉的变化而变化

时间:2016-01-24 17:15:32

标签: android android-fragments navigation-drawer screen-rotation

CURRENT SCENARIO

在我的应用程序中,我有带有碎片的导航抽屉。在肖像模式下一切正常。

问题

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

我知道我必须为片段保存实例但我不知道该怎么做,我应该在主要活动中还是片段本身

5 个答案:

答案 0 :(得分:3)

您应该在Fragment

中执行此操作

请点击以下链接:

Android - save/restore fragment state

或者也许:

Once for all, how to correctly save instance state of Fragments in back stack?

另外,让我们提一下onRestoreInstanceStateFragment没有那个方法。所以,你应该使用onActivityCreated来获得一个bundle来保存实例state(或null)。

查看文档:

http://developer.android.com/reference/android/app/Fragment.html#onActivityCreated(android.os.Bundle)

答案 1 :(得分:3)

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

How to keep the same fragment when activity restarts due to orientation change in a Navigation Drawer Activity

我试图解释为什么我提供的解决方案有效,所以如果你有兴趣检查一下。

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

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

这样当我们在第二个

中更改方向时,它不会使第一个片段膨胀

答案 2 :(得分:1)

我使用名为ViewModel class的新工具找到了更好的解决方案。屏幕旋转时,它将自动销毁deactivity并再次创建它,因此我们失去了最后选择的片段的焦点。 ViewModel帮助我们保留数据,它对于表单也是如此。

  1. 创建一个名为MainActivityViewModel.kt的类
  2. 将此代码放入其中:

    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. 然后创建一个加载默认片段的函数:

    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 -> { // default fragment if you consider necessary } } }

在初始化ViewModel后,必须将此函数调用到您的onCreate方法中。

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

override fun onNavigationItemSelected(item: MenuItem): Boolean { // Handle navigation view item clicks here. vm.menuItem = item.itemId // rest of the code ... }

现在,当旋转屏幕时,可以使用viewmodel值保存位置,也可以将其用于表单。

答案 3 :(得分:0)

更改配置后,导航控制器后堆栈有问题

在带有片段的活动中:尝试在更改配置之前保存导航控制器状态。更改配置后,再次将其添加回导航控制器。喜欢:

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"))}

那是我的情况

答案 4 :(得分:0)

新的Android体系结构组件引入了ViewModel类,该类有助于创建生命周期感知的组件。它解决了有关生命周期管理的大多数问题。如果在项目中使用Java代码,则可以引入ViewModel类。请按照下列步骤操作:

  1. 将此添加到您的 build.gradle(应用模块)

    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    
  2. 将此添加到您的 build.gradle(项目模块)

    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) {
    // load 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);
    }
    //you can add or exclude other  fragments here depending on your requirements
    }
    
  7. 最后,每次选择新菜单项时,我们都必须更新viewModel值,因此 修改覆盖方法 onNavigationItemSelected ,将其添加到开头:

    // Handle navigation view item clicks here.
    vm.setMenuItem(item.getItemId());