界面上需要实现如下图所示的效果:
界面上有Spinner用于选择波形的类型,Spinner的左边有一方块,用于表示波形的颜色。界面上总共有4个通道可选。该4个通道的样式一样,故编写了一个wave_channel_choose.xml文件,如下所示:
界面上4个通道选择中的spinner选择后,滑动界面,直到该界面被销毁,重新进入该界面,所有的spinner上的选项均变成与最后一个spinner的选项一样,不管界面上有多少个wave_channel_choose,界面销毁后重新进入界面,spinner的选项总是变成与最后一个一样。
为查原因,为每个spinner添加了监听事件,发现每一个spinner均会两次进入onItemSelected()函数,并且两次进入该函数的时候,选中的选项值是一样的。官方文档上说选择选项与原来不一样的时候,才会触发监听事件,调用onItemSelected()。实际实验的结果与官方文档描述地不一致。这点我无法解释,尚不知为何。
在Android系统中,页面销毁的时候,一般会调用onSaveInstanceState()函数,将目前页面上控件的状态保存下来,以用于下次构建页面的时候,恢复控件的状态。比如当前EditText的显示内容、Spinner的当前选项等。但是这个作用,应该指的是对当前页面的直接控件有效,即在XML文件中直接写入的控件,而不是通过include属性包含其他的xml文件中控件的子控件。
直接在xml文件放置4个Spinner控件,滑动页面。滑动到前第3个页面,当前页面销毁,确定再进入时,会重新构建。发现Spinner确实会保存页面销毁前的状态。监听这4个Spinner,每次重建页面后,会调用两次onItemSelected(),并且两次调用时,选择的选项位置是一样的。
网上搜索关键字“onItemSelected() 两次进入”,找到了解决方案:增加函数“spinner.setSelection(0,false);”。实际使用发现调用setSelection(int ,boolean)函数,第2个参数是false还是true都是可以的。但是一定要调用有两个参数的,调用setSelection(int)依然还是会两次进入onItemSelected()。而且函数的调用是要在设置监听器之前,否则也是无效的。
spinner.setSelection(0,false);
spinner.setOnItemSelectedListener(this);
用include导入的xml文件相当于自定义控件,系统无法正确保存控件的状态。因此重写onSaveInstanceState()函数,增加4个Spinner的状态,onCreateView()中读取savedInstanceState中的状态,赋值给spinner。发现再次进入页面,自定义xml中的spinner的选中项依然是所有控件都被最后一个影响,显示的选项均与退出页面前的最后一个选项一样。
在onResume()函数中,分别读取每个spinner的值,打印出来,发现确实是退出页面前的值,但后来又调用了函数onItemSelected(),选中的选项均是最后一个spinner的值。所以导致页面上显示的4个spinner选择均与最后一个一样。
onResume()是页面变为有效前调用的函数,因此在该函数中增加语句,将每个spinner当前的item值,读出来后,重新设置给各个spinner。
@Override
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
Spinner spinner = null;
int item = 0;
for (int i=0; i
item = i;
spinner = (Spinner)getView().findViewWithTag(i);
item = spinner.getSelectedItemPosition();
//该语句保证spinner上显示的选项不受最后一个spinner的影响。
//如果为spinner在onCreateView中设置初始值在监听函数之前,
//以下语句还能防止两次进入onItemSelected()函数
spinner.setSelection(item);
}
} }