使用暴力反射让Spinner选择同一选项时触发onItemSelected事件

我们的客户有时候是变态的,导致需求有时候也是变态的,比如这次项目,使用Spinner选择城市,要求每选择一次城市,就要重新加载一次数据,就算与上一次选择的是同一个城市,也要刷新数据。可是android的Spinner本身记住了上一次选择的项,再次选择同一项不会触发onItemSelected事件。

翻看源码,Spinner判断是否触发onItemSelected,是在它的基类AdapterView里面做的:

    void checkSelectionChanged() {
        if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
            selectionChanged();
            mOldSelectedPosition = mSelectedPosition;
            mOldSelectedRowId = mSelectedRowId;
        }
    }

方法checkSelectionChanged和变量mOldSelectedPosition都是AdapterView私有的,我们无法继承Spinner重写之。不过,利用java的反射,我们可以暴力修改mOldSelectedPosition的值:

	new OnItemSelectedListener() {

		@Override
		public void onItemSelected(AdapterView arg0, View arg1,
				int arg2, long arg3) {
			// TODO Auto-generated method stub
			try {
				//以下三行代码是解决问题所在
				Field field = AdapterView.class.getDeclaredField("mOldSelectedPosition");
				field.setAccessible(true);	//设置mOldSelectedPosition可访问
				field.setInt(spinner, AdapterView.INVALID_POSITION); //设置mOldSelectedPosition的值
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		@Override
		public void onNothingSelected(AdapterView arg0) {
			// TODO Auto-generated method stub
			
		}
	};

我们每次选择之后,就更改mOldSelectedPosition的值,使得每次mSelectedPosition != mOldSelectedPosition判断总是为true,那么总会触发onItemSelected,达到我们的目的了。

java的反射是十分强大的,一看到私有的变量或方法,都可以利用反射访问。所以说,反射在手,天下我有。



你可能感兴趣的:(android)