Fragment的状态保存
在fragment状态保存之前先来了解以下Activity的状态保存:
Activity有两个方法应用恢复和保存状态,他们分别是:
override fun onSaveInstanceState(outState: Bundle)
{
super.onSaveInstanceState(outState,)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle)
{
super.onRestoreInstanceState(savedInstanceState)
}
当配置发生变化时会默认调用 Activity.onSaveInstanceState()
方法,我们可以使用outState参数来保存状态,同样在重新创建时会调用Activity.onRestoreInstanceState()
用来恢复数据。
在Fragment中也有相同的onSaveInstanceState()
方法用于保存数据,但不同的是恢复在FragmentonCreate(Bundle)
、onCreateView(LayoutInflater, ViewGroup, Bundle)
和 onViewCreated(View, Bundle)
方法中可用于恢复状态。
Fragment什么时候需要保存状态?
当发生以下四件事的时候Fragment的状态将会重建:
-
按HOME键返回桌面时
-
按菜单键回到系统后台,并选择了其他应用时
-
按电源键时
-
屏幕方向切换时
前三种状态App将会在后台运行,状态的重建取决于Android的缓存机制,当缓存不足时,后台程序很大概率可能会被清除,一旦app被清除那么状态就会销毁。屏幕方向的转变也会重新构建Fragment。
在这些情况下我们就可以使用状态保存机制来保存Fragment中的数据,
在此之前,我们先来看几种情况:
1.在Fragment中添加一个EditText不设置ID,在将Fragment添加到Activity中,运行后在EditText中输入数据,然后将手机横屏,这时候我们发现EditText中的数据消失了,我们看到这次Fragment没有为我们保存状态。
2.在Fragment中添加一个EditText这次我们设置一个ID,在将Fragment添加到Activity中,运行后在EditText中输入数据,然后将手机横屏,这时候我们发现EditText中的数据依然存在。
3.在Fragment中添加一个EditText,一个Button,一个TextView,分别给三个控件设置ID,在将Fragment添加到Activity中,运行后在EditText中输入数据,然后点击Button后将EditText中的数据赋值到TextView上,我们转换屏幕发现这时候EditText中的数据保存了,但是TextView中的数据没有保存。
通过1,2我们发现没有使用onSaveInstanceState的时候居然也可以保存状态,而且还与ID有关。但是通过2和3我们发现不仅与ID有关,还与其他配置有关,这是怎么回事呢?
原来在Android当中,在Activity的onSavelnstanceState()
方法在调用时会自动收集每个View的状态,注意只有在内部实现了恢复和实现方法的View才可以收集到,一旦onRestoreInstanceState()
被调用,Activity会把收集到的数据发送回给View结构树中具有相同ID的View,于是就这样数据被保存了下来。
注意两点:
1.View中必须实现了保存和恢复状态方法
override fun onSaveInstanceState(): Parcelable?
{
return super.onSaveInstanceState()
}
override fun onRestoreInstanceState(state: Parcelable?)
{
super.onRestoreInstanceState(state)
}
所以我们在使用自定义View的时候也要实现这两个方法
2.必须有Android:id
同时我们发现在Fragment返回栈中的保存机制与转换屏幕一致,我们创建了一个新的Fragment通过底部的按钮在两个Fragment之间转换,转换使用supportFragmentManager.replac()
方法并且每一次转换都把Fragment事务加入到返回栈中,开始运行,和上次操作一样,在EditText中输入数据,再点击Button后将EditText中的数据赋值到TextView上,在点击Fragment2跳转到Fragment2中,点击回退按钮,发现Text没有保存,但是EditText保存了。