运行时配置变更
有些配置可能会在运行时候发生变化(屏幕方向,键盘和语言),发生变化时,android会重启正在运行的activity(先后调用onPause,onStop,onDestory,onCreate,onStart,onResume),重启是为了加载新资原适应新配置.
为了更好地处理重启行为,activity必须通过常规的生命周期恢复其以前的状态,android会在activity被销毁之前调用onSaveInstanceState(),来保存应用状态的数据,然后你可在onCreate()或onRestoreInstanceState()期间恢复状态.
但是,假如遇到重启并恢复大量数据不仅成本高昂,而且可能导致用户体验不佳,这种情况下,你可以:
配置变更时保留对象
允许activity在配置变更时重启,但是要将状态对象传递给activity的新实例.
自行处理配置变更
阻止系统在某些配置变更时重启activity,但是在配置确实发生变化时接收回调,根据需求手动更新activity
在配置变更期间保留对象
如果重启activity需要恢复大量数据,重新建立网络连接或其它耗时操作,那么配置变更会给用户带来不好的体验,而且,仅仅依靠onSaveInstanceState()回调保存的Bundle,可能无法完全恢复,无法携带大型对象(bitmap),这种情况下,可以通过保留Fragment来减轻初始化activity的负担,此片段可能包含你对保留的有状态对象的引用.
要将有状态的对象保留在Fragment片段中,请执行下列操作:
扩展Fragment类并声明对有状态对象的引用.
在创建片段后调用setRetainInstance(boolean)
将片段添加到activity
重启activity后,使用FragmentManager检索片段.
示例:
public class RetainedFragment extends Fragment {
// 要存放的数据对象
private MyDataObject data;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 保留这个片段
setRetainInstance(true);
}
public void setData(MyDataObject data) {
this.data = data;
}
public MyDataObject getData() {
return data;
}
}
public class MyActivity extends Activity {
private RetainedFragment dataFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 在activity重启时查找保存的片段
FragmentManager fm = getFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
// 第一次创建对象和保存的数据
if (dataFragment == null) {
// add the fragment
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, “data”).commit();
// load the data from the web
dataFragment.setData(loadMyData());
}
// 通过dataFragment.getData()可以访问数据
...
}
@Override
public void onDestroy() {
super.onDestroy();
// 保存数据到片段
dataFragment.setData(collectMyLoadedData());
}
}
自行处理配置变更
如果应用在特定配置变更期间无需更新资源,或者因为性能限制要尽量避免重启,则可声明activity将自行处理变更.
清单文件的activity元素的android:configChanges属性,常用值有
fontScale 改变全局字体大小
orientation 屏幕的方向变化
keyboardHidden 键盘的可访问性变化
keyboard 键盘类型发生变化
locale 地区更改,用户选择一个新的语言
screenSize 屏幕的大小变化
你可以设置多值,比如
android:configChanges=”orientation|keyboardHidden”
现在,其中一个配置发生变化时,activity不会重启,而是收到对onConfigurationChanged()的调用,向此方法传递Configuration对象指定新设备配置,你可以通过读取Configuration的字段,确定新配置,然后通过更新界面中使用的资源进行适当的更改,调用这个方法时,activity的Resources对象会相应地进行更新,根据新配置返回资源,这样,你就能在不重启activity的情况下轻松重置UI的元素.
注意:从API13开始,设备方向变化时,屏幕尺寸也会发生变化,所以除了设置orientation之外还有设置screenSize的值.
示例(检查方向):
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// 检查屏幕的方向
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}