CURRENT SCENARIO
在我的应用程序中,我有带有碎片的导航抽屉。在肖像模式下一切正常。
问题
假设在纵向模式下我从导航栏中选择第二项。它可以很好地加载,但是当我将手机旋转到横向模式时,导航菜单中的第一个片段会被加载而不是第二个。
我知道我必须为片段保存实例但我不知道该怎么做,我应该在主要活动中还是片段本身
答案 0 :(得分:3)
您应该在Fragment
。
请点击以下链接:
Android - save/restore fragment state
或者也许:
Once for all, how to correctly save instance state of Fragments in back stack?
另外,让我们提一下onRestoreInstanceState
,Fragment
没有那个方法。所以,你应该使用onActivityCreated
来获得一个bundle
来保存实例state(或null)。
查看文档:
答案 1 :(得分:3)
我在这个帖子中回答了同样的问题:
我试图解释为什么我提供的解决方案有效,所以如果你有兴趣检查一下。
要解决这个问题,我只需将初始片段膨胀的代码放在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帮助我们保留数据,它对于表单也是如此。
MainActivityViewModel.kt
的类将此代码放入其中:
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
vm = ViewModelProviders.of(this).get(MainActivityViewModel::class.java)
然后创建一个加载默认片段的函数:
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类。请按照下列步骤操作:
将此添加到您的 build.gradle(应用模块)
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
将此添加到您的 build.gradle(项目模块)
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) {
// load 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);
}
//you can add or exclude other fragments here depending on your requirements
}
最后,每次选择新菜单项时,我们都必须更新viewModel值,因此 修改覆盖方法 onNavigationItemSelected ,将其添加到开头:
// Handle navigation view item clicks here.
vm.setMenuItem(item.getItemId());