处理Runtime Changed的官方建议

一般情况下我们应用的配置发生了改变的话,activity会被destory掉(目的是为了让应用去适应新的配置环境),然后重开启一个activty,这就涉及到数据存储的问题了。

一般情况下: activity在发生异常的时候,会先执行onSaveInstanceState()的,把我们的数据存进去,然后在onCreate(Bundle savedInstanceState)或者onRestoreInstanceState(Bundle savedInstanceState)的时候从bundle取出来就可以了,但onSaveInstanceState()只是适合小数据量的情况。如果数据量很大的话,比如说一个复杂的listView里面的item数据(比如说包含了bitmap),是否也要花一大部分代码去存储数据状态呢?显然是不对的,这样太占用内存了。
解决方案有两个

用fragment的形式存储相应数据的references(保证数据不被gc,当然也要保证这个fragment在activity 重新创建的时候不被回收),然后根据referneces来取出数据。fragment的设计如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class RetainedFragment extends Fragment {
//持有对应数据的references,需要注意的是
//这个data应该完全独立于activity,context.否则导致内存泄漏
private MyDataObject data;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 即使附着的activity被re-creation了这个fragment依然还可使用
setRetainInstance(true);
}
public void setData(MyDataObject data) {
this.data = data;
}
public MyDataObject getData() {
return data;
}
}
在activity中利用这个fragment存储数据
public class MyActivity extends Activity {
private RetainedFragment dataFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager fm = getFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
// 在activity创建的时候就初始化这个fragment
if (dataFragment == null) {
// 附着fragment到当前activity上去
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, “data”).commit();
//从web上获取相应数据
dataFragment.setData(loadMyData());
}
// the data is available in dataFragment.getData()
//Data data = dataFragment.getData();...
//loadData()-->reshow all data
}
@Override
public void onDestroy() {
super.onDestroy();
// store the data in the fragment
dataFragment.setData(collectMyLoadedData());
}
}

  • 自己来处理配置改变的情况,不要去resatart这个activity自己复写这个函数就好了,因为系统在这个函数里面执行销毁并重建activity的操作,传进来的newConfig对象包含了所有的变动的config信息,弄一个switch来筛选下需要覆盖的config变动就好
1
2
3
4
5
6
7
8
9
@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();
}
}