当前情况
我的应用程序中有一个带有片段的导航抽屉。在纵向模式下一切正常。
问题
假设我在纵向模式下从导航抽屉中选择第二个项目。它可以完美地加载,但是当我将手机旋转到横向模式时,导航菜单中的第一个片段会被加载而不是第二个片段。
我知道我必须保存片段实例,但我不知道如何做,我应该在主活动中还是在片段本身中进行保存?
当前情况
我的应用程序中有一个带有片段的导航抽屉。在纵向模式下一切正常。
问题
假设我在纵向模式下从导航抽屉中选择第二个项目。它可以完美地加载,但是当我将手机旋转到横向模式时,导航菜单中的第一个片段会被加载而不是第二个片段。
我知道我必须保存片段实例,但我不知道如何做,我应该在主活动中还是在片段本身中进行保存?
我在这个帖子中回答了同样的问题:
我试图解释为什么我提供的解决方案有效,所以如果你感兴趣就去看看吧。
为了解决这个问题,我只需将膨胀初始片段的代码放在一个if语句中(在导航抽屉活动的OnCreate中):
super.onCreate(savedInstanceState);
if(savedInstanceState==null){
FragmentManager fM = getSupportFragmentManager();
fM.beginTransaction().replace(R.id.NavDrawContent,new home_fragment()).commit();
}
你应该在你的Fragment
中这样做。
只需按照以下链接:
或者也许是:
此外,让我们提到onRestoreInstanceState
,Fragment
没有这个方法。所以,你应该使用onActivityCreated
来接收一个保存的实例状态的bundle
(或null)。
看一下文档:
R.id.nav_inicio
作为默认菜单项,根据您的activity_main_drawer.xml(Android Studio的默认名称)进行修改。lateinit var vm:MainActivityViewModel
vm = ViewModelProviders.of(this).get(MainActivityViewModel::class.java)
然后创建一个函数来加载默认的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值会保存位置,您可以在表单中使用它。
更改配置后,导航控制器返回栈存在问题。
在带有片段的活动中:尝试在更改配置之前保存导航控制器状态。更改配置后,将其重新添加到导航控制器中。例如:
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"))}
将以下代码添加到您的build.gradle(app module)文件中
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
将以下代码添加到您的build.gradle(project module)文件中
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"
}
创建一个名为MainActivityViewModel.kt的新类,并使用以下代码
class MainActivityViewModel : ViewModel() {
var menuItem: Int = R.id.nav_home
}
在您的MainActivity.java文件中,在类的顶部添加以下代码
private MainActivityViewModel vm;
并在MainActivity.java onCreate方法中添加以下代码
vm = new ViewModelProvider(this).get(MainActivityViewModel.class);
loadDefaultFragment();
现在,在您的MainActivity.java文件中创建一个名为loadFragment()的方法,并使用以下代码
private void loadFragment(Fragment fragment) {
// 加载fragment
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.contentMainLayout, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
在您的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
}
最后,每次选择新菜单项时,我们都必须更新viewModel值,因此在onNavigationItemSelected方法的开头进行修改:
// 在此处理导航视图项单击。
vm.setMenuItem(item.getItemId());