为什么即使事件setOnItemSelectedListener在setSelection之后,Spinner控件仍然显示提示信息?

Hel*_*oCW 9 android

我在spinnerRanger.setSelection之后编写Spinner的事件setOnItemSelectedListener.

我认为Toast.makeText(...)第一次运行APP时不会启动,但仍会显示提示信息,为什么?

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.cleanup_delete_fragment_old, container, false);

    mView = rootView;
    mContext = rootView.getContext();

    InitValueOfControls();
    return rootView;
}

private void InitValueOfControls() {
    spinnerRanger = (Spinner)mView.findViewById(R.id.spinner);
    PublicParFun.FillRangeSpinner(mView, spinnerRanger);
    spinnerRanger.setSelection(PublicParFun.GetIndexOfRangeDeleteOld(mContext));
    spinnerRanger.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            Toast.makeText(mContext, "My "+position, Toast.LENGTH_LONG).show();
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

致Trevor Carothers:

如果我DoLongTimeOperation()Selection侦听器事件之前插入一个 ,它还会显示toast吗?

private void InitValueOfControls() {
    spinnerRanger = (Spinner)mView.findViewById(R.id.spinner);
    PublicParFun.FillRangeSpinner(mView, spinnerRanger);
    spinnerRanger.setSelection(PublicParFun.GetIndexOfRangeDeleteOld(mContext));

    DoLongTimeOperation();

    spinnerRanger.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            Toast.makeText(mContext, "My " + position, Toast.LENGTH_LONG).show();
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

代码A:

private void InitValueOfControls() {
    spinnerRanger = (Spinner)mView.findViewById(R.id.spinner);
    PublicParFun.FillRangeSpinner(mView, spinnerRanger);
    spinnerRanger.setSelection(PublicParFun.GetIndexOfRangeDeleteOld(mContext));

    DoLongTimeOperation();

    spinnerRanger.post(new Runnable() {
        @Override
        public void run() {
            spinnerRanger.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                    Toast.makeText(mContext, "My "+position, Toast.LENGTH_LONG).show();
                }

                @Override
                public void onNothingSelected(AdapterView<?> parent) {
                }
            });
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

代码B.

private void InitValueOfControls() {
    spinnerRanger = (Spinner)mView.findViewById(R.id.spinner);
    PublicParFun.FillRangeSpinner(mView, spinnerRanger);
    spinnerRanger.setSelection(PublicParFun.GetIndexOfRangeDeleteOld(mContext));
    spinnerRanger.post(new Runnable() {
        @Override
        public void run() {
            spinnerRanger.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                // ...
            }
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

代码C.

private void InitValueOfControls() {
    spinnerRanger = (Spinner)mView.findViewById(R.id.spinner);
    PublicParFun.FillRangeSpinner(mView, spinnerRanger);
    spinnerRanger.setSelection(PublicParFun.GetIndexOfRangeDeleteOld(mContext));
    spinnerRanger.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        // ...
    });
}
Run Code Online (Sandbox Code Playgroud)

Tre*_*ers 4

我只是使用自己的基本 ArrayAdapter 运行此代码,当创建视图并在设置侦听器之前调用 setSelection() 时,它会立即显示 toast(如上面所示)。

这绝对是不直观的,因为您是在设置选择之后设置侦听器。深入了解它的唯一方法是深入研究源代码。经过一番翻阅后,我发现他们将此Runnable发布到主线程以通知侦听器选择更改。这是事件的顺序:

  1. 旋转视图膨胀
  2. 适配器(数据源)集
  3. 选择集和 SelectionNotifier Runnable 已发布
  4. 在 Spinner 上设置选择侦听器
  5. 在主线程上处理的 SelectionNotifier
  6. SelectionNotifier 调用 onItemSelected() 并显示 Toast

发布一个 Runnable 来设置您的选择侦听器,以便在第一次传递的 SelectionNotifier 之后对其进行处理:

private void InitValueOfControls()
{
    spinnerRanger=(Spinner)mView.findViewById(R.id.spinner);
    PublicParFun.FillRangeSpinner(mView, spinnerRanger);

    spinnerRanger.setSelection(PublicParFun.GetIndexOfRangeDeleteOld(mContext));
    spinnerRanger.post(new Runnable() {
    @Override
        public void run() {
            spinnerRanger.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {...}
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

新的事件顺序是:

  1. 旋转视图膨胀
  2. 适配器(数据源)集
  3. 选择集和 SelectionNotifier Runnable 已发布
  4. 已发布可运行以在 Spinner 上设置选择侦听器
  5. 在主线程上处理的 SelectionNotifier
  6. SelectionNotifier 没有要通知的侦听器,因此它不执行任何操作。没有显示 TOAST!
  7. 我们在 Spinner 上设置选择侦听器的 Runnable 在主线程上进行处理,并设置选择侦听器