Android Spinner 的 onItemSelected 在返回 Fragment 时执行了两次
Android Spinner's onItemSelected executed twice when going back to Fragment
我为我的 Fragment 创建了一个微调器,用从 HTTP 标注中检索到的数据填充它。首次创建片段时,我用它的选择选项填充微调器,设置它的 setOnItemSelectedListener 并在 onCreateView() 中设置它的初始选择。
stateSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
if (spinnerPosition != position)
{
spinnerPosition = position;
TextView stateSelected = (TextView) view;
String stateSelectedStr = stateSelected.getText().toString();
LinearLayout ballotsDisplay = (LinearLayout) getActivity().findViewById(R.id.ballotsDisplay);
ballotsDisplay.removeAllViews();
Map<String, String> calloutParams = new HashMap<String, String>();
calloutParams.put("state", stateSelectedStr);
// Create and execute AsyncTask to retrieve ballots
new RetrieveBallots().execute(calloutParams);
}
}
public void onNothingSelected(AdapterView<?> parent) {
return;
}
});
// Set default selection for spinner
int defaultState = adapter.getPosition(userState);
if (defaultState == -1)
{
defaultState = 0;
}
stateSpinner.setSelection(defaultState);
创建片段后,一切正常,微调器位置设置为默认值,微调器项目被选中一次,如下面的日志所示:
5009-5009/com.project.test D/TEST﹕ onCreateView called
5009-5009/com.project.test D/TEST﹕ stateSpinner.setSelection
5009-5009/com.project.test D/TEST﹕ onActivityCreated called
5009-5009/com.project.test D/TEST﹕ onResume called
5009-5009/com.project.test D/TEST﹕ spinner item selected
当我从 Fragment 导航到另一个 fragment(我将 fragment 存储到 backstack 上)时出现问题。当我单击返回返回到我原来的片段时,微调器似乎选择了它的项目两次:
5009-5009/com.project.test D/TEST﹕ onCreateView called
5009-5009/com.project.test D/TEST﹕ stateSpinner.setSelection
5009-5009/com.project.test D/TEST﹕ onActivityCreated called
5009-5009/com.project.test D/TEST﹕ onResume called
5009-5009/com.project.test D/TEST﹕ spinner item selected
5009-5009/com.project.test D/TEST﹕ spinner item selected
所以我有两个问题:
1) 为什么微调器在从“后退”按钮返回时会记录 2 次项目选择事件。
2) 是否有防止出现 2 项选择的修复程序?现在片段正在填充重复数据,因为它检索数据两次。
** 编辑 **
更改为 stateSpinner.setSelection(defaultState, false)
后,我会在 ballotsDisplay.removeAllViews();
处得到一个空指针异常,似乎 ballotsDisplay 由于某种原因被设置为 null
堆栈跟踪:
05-15 07:25:48.303 6153-6153/com.poliseewriters.polisee E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NullPointerException
at com.polisee.ballotmeasures.BallotMeasuresFragment.onItemSelected(BallotMeasuresFragment.java:287)
at android.widget.AdapterView.fireOnSelected(AdapterView.java:882)
at android.widget.AdapterView.selectionChanged(AdapterView.java:865)
at android.widget.AdapterView.checkSelectionChanged(AdapterView.java:1017)
at android.widget.Spinner.layout(Spinner.java:363)
at android.widget.AbsSpinner.setSelectionInt(AbsSpinner.java:292)
at android.widget.AbsSpinner.setSelection(AbsSpinner.java:269)
at com.polisee.ballotmeasures.BallotMeasuresFragment.setStateSpinner(BallotMeasuresFragment.java:314)
at com.polisee.ballotmeasures.BallotMeasuresFragment.onCreateView(BallotMeasuresFragment.java:201)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1786)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:953)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1136)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:739)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1499)
at android.support.v4.app.FragmentManagerImpl.run(FragmentManager.java:456)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4441)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
** 编辑:更新代码以防止 onItemSelected 执行两次,需要为 ballotsDisplay 添加空检查 **
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if (savedInstanceState != null) {
Log.d("TEST", "bundle = " + savedInstanceState.toString());
}
Log.d("TEST", "onCreateView called");
View view = (View) inflater.inflate(R.layout.fragment_ballot_measures, container, false);
setStateSpinner(view);
return view;
}
private void setStateSpinner(View view) {
try {
states = Utilities.getAllStateNames();
}
catch (Exception e) {
Log.e("Error", "Error retrieving names: " + e.getMessage());
}
Spinner stateSpinner = (Spinner) view.findViewById(R.id.stateSpinner);
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), R.layout.ballotmeasures_state_spinner, states);
adapter.setDropDownViewResource(R.layout.ballotmeasures_state_spinner_dropdown);
stateSpinner.setAdapter(adapter);
stateSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
// Callback method to invoke when a state has been selected
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
Log.d("TEST", "spinner item selected");
TextView stateSelected = (TextView) view;
String stateSelectedStr = stateSelected.getText().toString();
// Remove all currently displayed views in the layout
LinearLayout ballotsDisplay = (LinearLayout) getActivity().findViewById(R.id.ballotsDisplay);
if (ballotsDisplay != null)
{
ballotsDisplay.removeAllViews();
}
Map<String, String> calloutParams = new HashMap<String, String>();
calloutParams.put("state", stateSelectedStr);
// AsyncTask to execute data retrieval
new RetrieveBallots().execute(calloutParams);
}
public void onNothingSelected(AdapterView<?> parent) {
return;
}
});
// Set default selection for spinner
int defaultState = adapter.getPosition(userState);
if (defaultState == -1)
{
defaultState = 0;
}
Log.d("TEST", "stateSpinner.setSelection");
stateSpinner.setSelection(defaultState, false);
}
用stateSpinner.setSelection(defaultState, false);
代替stateSpinner.setSelection(defaultState);
问题是 onItemSelected()
回调被 Android 框架调用两次(可能是设计使然),第一次 view
参数是 null
,并且第二次实例化。
您无法阻止出现 2 项选择,但您可以检查 view
变量是否为空,如果不是,则执行其余操作。
像这样在 ItemSelectedListener 中添加条件视图!=null:
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(view!=null)
{//write your code
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
我为我的 Fragment 创建了一个微调器,用从 HTTP 标注中检索到的数据填充它。首次创建片段时,我用它的选择选项填充微调器,设置它的 setOnItemSelectedListener 并在 onCreateView() 中设置它的初始选择。
stateSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
if (spinnerPosition != position)
{
spinnerPosition = position;
TextView stateSelected = (TextView) view;
String stateSelectedStr = stateSelected.getText().toString();
LinearLayout ballotsDisplay = (LinearLayout) getActivity().findViewById(R.id.ballotsDisplay);
ballotsDisplay.removeAllViews();
Map<String, String> calloutParams = new HashMap<String, String>();
calloutParams.put("state", stateSelectedStr);
// Create and execute AsyncTask to retrieve ballots
new RetrieveBallots().execute(calloutParams);
}
}
public void onNothingSelected(AdapterView<?> parent) {
return;
}
});
// Set default selection for spinner
int defaultState = adapter.getPosition(userState);
if (defaultState == -1)
{
defaultState = 0;
}
stateSpinner.setSelection(defaultState);
创建片段后,一切正常,微调器位置设置为默认值,微调器项目被选中一次,如下面的日志所示:
5009-5009/com.project.test D/TEST﹕ onCreateView called
5009-5009/com.project.test D/TEST﹕ stateSpinner.setSelection
5009-5009/com.project.test D/TEST﹕ onActivityCreated called
5009-5009/com.project.test D/TEST﹕ onResume called
5009-5009/com.project.test D/TEST﹕ spinner item selected
当我从 Fragment 导航到另一个 fragment(我将 fragment 存储到 backstack 上)时出现问题。当我单击返回返回到我原来的片段时,微调器似乎选择了它的项目两次:
5009-5009/com.project.test D/TEST﹕ onCreateView called
5009-5009/com.project.test D/TEST﹕ stateSpinner.setSelection
5009-5009/com.project.test D/TEST﹕ onActivityCreated called
5009-5009/com.project.test D/TEST﹕ onResume called
5009-5009/com.project.test D/TEST﹕ spinner item selected
5009-5009/com.project.test D/TEST﹕ spinner item selected
所以我有两个问题:
1) 为什么微调器在从“后退”按钮返回时会记录 2 次项目选择事件。
2) 是否有防止出现 2 项选择的修复程序?现在片段正在填充重复数据,因为它检索数据两次。
** 编辑 **
更改为 stateSpinner.setSelection(defaultState, false)
后,我会在 ballotsDisplay.removeAllViews();
处得到一个空指针异常,似乎 ballotsDisplay 由于某种原因被设置为 null
堆栈跟踪:
05-15 07:25:48.303 6153-6153/com.poliseewriters.polisee E/AndroidRuntime﹕ FATAL EXCEPTION: main java.lang.NullPointerException at com.polisee.ballotmeasures.BallotMeasuresFragment.onItemSelected(BallotMeasuresFragment.java:287) at android.widget.AdapterView.fireOnSelected(AdapterView.java:882) at android.widget.AdapterView.selectionChanged(AdapterView.java:865) at android.widget.AdapterView.checkSelectionChanged(AdapterView.java:1017) at android.widget.Spinner.layout(Spinner.java:363) at android.widget.AbsSpinner.setSelectionInt(AbsSpinner.java:292) at android.widget.AbsSpinner.setSelection(AbsSpinner.java:269) at com.polisee.ballotmeasures.BallotMeasuresFragment.setStateSpinner(BallotMeasuresFragment.java:314) at com.polisee.ballotmeasures.BallotMeasuresFragment.onCreateView(BallotMeasuresFragment.java:201) at android.support.v4.app.Fragment.performCreateView(Fragment.java:1786) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:953) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1136) at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:739) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1499) at android.support.v4.app.FragmentManagerImpl.run(FragmentManager.java:456) at android.os.Handler.handleCallback(Handler.java:605) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4441) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) at dalvik.system.NativeStart.main(Native Method)
** 编辑:更新代码以防止 onItemSelected 执行两次,需要为 ballotsDisplay 添加空检查 **
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if (savedInstanceState != null) {
Log.d("TEST", "bundle = " + savedInstanceState.toString());
}
Log.d("TEST", "onCreateView called");
View view = (View) inflater.inflate(R.layout.fragment_ballot_measures, container, false);
setStateSpinner(view);
return view;
}
private void setStateSpinner(View view) {
try {
states = Utilities.getAllStateNames();
}
catch (Exception e) {
Log.e("Error", "Error retrieving names: " + e.getMessage());
}
Spinner stateSpinner = (Spinner) view.findViewById(R.id.stateSpinner);
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), R.layout.ballotmeasures_state_spinner, states);
adapter.setDropDownViewResource(R.layout.ballotmeasures_state_spinner_dropdown);
stateSpinner.setAdapter(adapter);
stateSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
// Callback method to invoke when a state has been selected
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
Log.d("TEST", "spinner item selected");
TextView stateSelected = (TextView) view;
String stateSelectedStr = stateSelected.getText().toString();
// Remove all currently displayed views in the layout
LinearLayout ballotsDisplay = (LinearLayout) getActivity().findViewById(R.id.ballotsDisplay);
if (ballotsDisplay != null)
{
ballotsDisplay.removeAllViews();
}
Map<String, String> calloutParams = new HashMap<String, String>();
calloutParams.put("state", stateSelectedStr);
// AsyncTask to execute data retrieval
new RetrieveBallots().execute(calloutParams);
}
public void onNothingSelected(AdapterView<?> parent) {
return;
}
});
// Set default selection for spinner
int defaultState = adapter.getPosition(userState);
if (defaultState == -1)
{
defaultState = 0;
}
Log.d("TEST", "stateSpinner.setSelection");
stateSpinner.setSelection(defaultState, false);
}
用stateSpinner.setSelection(defaultState, false);
代替stateSpinner.setSelection(defaultState);
问题是 onItemSelected()
回调被 Android 框架调用两次(可能是设计使然),第一次 view
参数是 null
,并且第二次实例化。
您无法阻止出现 2 项选择,但您可以检查 view
变量是否为空,如果不是,则执行其余操作。
像这样在 ItemSelectedListener 中添加条件视图!=null:
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(view!=null)
{//write your code
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});