새로 인스턴스화 된 스피너에서 onItemSelected가 실행되지 않도록하는 방법은 무엇입니까? 뭔가 빠진 것이 틀림 없다는 것을 안다. 나의

나는 이것을 해결할 수있는 우아한 방법보다 덜 생각했지만, 뭔가 빠진 것이 틀림 없다는 것을 안다.

나의 onItemSelected 사용자와의 상호 작용없이 즉시 꺼 화재, 이것은 바람직하지 않은 동작입니다. UI가 사용자가 무언가를 선택할 때까지 기다렸다가 아무것도하지 않기를 바랍니다.

나는 심지어 청취자를 설정하려고 시도했다. onResume() 도움이되기를 기대하면서에 했지만 그렇지 않습니다.

사용자가 컨트롤을 터치하기 전에 발사를 중지하려면 어떻게해야합니까?

public class CMSHome extends Activity {

private Spinner spinner;

@Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // Heres my spinner ///////////////////////////////////////////
    spinner = (Spinner) findViewById(R.id.spinner);
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
            this, R.array.pm_list, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);
    };

public void onResume() {
    super.onResume();
    spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
}

    public class MyOnItemSelectedListener implements OnItemSelectedListener {

    public void onItemSelected(AdapterView<?> parent,
        View view, int pos, long id) {

     Intent i = new Intent(CMSHome.this, ListProjects.class);
     i.putExtra("bEmpID", parent.getItemAtPosition(pos).toString());
        startActivity(i);

        Toast.makeText(parent.getContext(), "The pm is " +
          parent.getItemAtPosition(pos).toString(), Toast.LENGTH_LONG).show();
    }

    public void onNothingSelected(AdapterView parent) {
      // Do nothing.
    }
}
}



답변

솔루션이 작동 할 것으로 예상했을 것입니다. 리스너를 설정하기 전에 어댑터를 설정하면 선택 이벤트가 실행되지 않습니다.

즉, 간단한 부울 플래그를 사용하면 악성 첫 번째 선택 이벤트를 감지하고 무시할 수 있습니다.


답변

Runnables 사용이 완전히 잘못되었습니다.

setSelection(position, false);초기 선택에서 사용setOnItemSelectedListener(listener)

이 방법으로 선택한 항목 리스너가 호출되게하는 애니메이션없이 선택을 설정합니다. 그러나 리스너가 null이므로 아무것도 실행되지 않습니다. 그런 다음 청취자가 할당됩니다.

따라서이 정확한 순서를 따르십시오.

Spinner s = (Spinner)Util.findViewById(view, R.id.sound, R.id.spinner);
s.setAdapter(adapter);
s.setSelection(position, false);
s.setOnItemSelectedListener(listener);


답변

댄 다이어의 대답을 참조하면, 등록하려고 OnSelectListenerA의 post(Runnable)방법 :

spinner.post(new Runnable() {
    public void run() {
        spinner.setOnItemSelectedListener(listener);
    }
});

그렇게함으로써 원하는 행동이 마침내 일어났습니다.

이 경우에도 리스너가 변경된 항목에서만 실행됨을 의미합니다.


답변

Spinner사용자에게 알리지 않고 선택 을 변경하는 작은 유틸리티 방법을 만들었습니다 .

private void setSpinnerSelectionWithoutCallingListener(final Spinner spinner, final int selection) {
    final OnItemSelectedListener l = spinner.getOnItemSelectedListener();
    spinner.setOnItemSelectedListener(null);
    spinner.post(new Runnable() {
        @Override
        public void run() {
            spinner.setSelection(selection);
            spinner.post(new Runnable() {
                @Override
                public void run() {
                    spinner.setOnItemSelectedListener(l);
                }
            });
        }
    });
}

리스너를 비활성화하고 선택을 변경 한 후 리스너를 다시 활성화합니다.

트릭은 호출이 UI 스레드와 비동기 적이므로 연속 처리기 포스트에서 호출해야합니다.


답변

불행히도이 문제에 대해 가장 일반적으로 제안되는 두 가지 솔루션, 즉 콜백 발생 수를 계산하고 나중에 콜백을 설정하기 위해 Runnable을 게시하면 접근성 옵션이 활성화 된 경우 모두 실패 할 수 있습니다. 이러한 문제를 해결하는 도우미 클래스가 있습니다. 추가 설명은 주석 블록에 있습니다.

import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;

/**
 * Spinner Helper class that works around some common issues
 * with the stock Android Spinner
 *
 * A Spinner will normally call it's OnItemSelectedListener
 * when you use setSelection(...) in your initialization code.
 * This is usually unwanted behavior, and a common work-around
 * is to use spinner.post(...) with a Runnable to assign the
 * OnItemSelectedListener after layout.
 *
 * If you do not call setSelection(...) manually, the callback
 * may be called with the first item in the adapter you have
 * set. The common work-around for that is to count callbacks.
 *
 * While these workarounds usually *seem* to work, the callback
 * may still be called repeatedly for other reasons while the
 * selection hasn't actually changed. This will happen for
 * example, if the user has accessibility options enabled -
 * which is more common than you might think as several apps
 * use this for different purposes, like detecting which
 * notifications are active.
 *
 * Ideally, your OnItemSelectedListener callback should be
 * coded defensively so that no problem would occur even
 * if the callback was called repeatedly with the same values
 * without any user interaction, so no workarounds are needed.
 *
 * This class does that for you. It keeps track of the values
 * you have set with the setSelection(...) methods, and
 * proxies the OnItemSelectedListener callback so your callback
 * only gets called if the selected item's position differs
 * from the one you have set by code, or the first item if you
 * did not set it.
 *
 * This also means that if the user actually clicks the item
 * that was previously selected by code (or the first item
 * if you didn't set a selection by code), the callback will
 * not fire.
 *
 * To implement, replace current occurrences of:
 *
 *     Spinner spinner =
 *         (Spinner)findViewById(R.id.xxx);
 *
 * with:
 *
 *     SpinnerHelper spinner =
 *         new SpinnerHelper(findViewById(R.id.xxx))
 *
 * SpinnerHelper proxies the (my) most used calls to Spinner
 * but not all of them. Should a method not be available, use:
 *
 *      spinner.getSpinner().someMethod(...)
 *
 * Or just add the proxy method yourself :)
 *
 * (Quickly) Tested on devices from 2.3.6 through 4.2.2
 *
 * @author Jorrit "Chainfire" Jongma
 * @license WTFPL (do whatever you want with this, nobody cares)
 */
public class SpinnerHelper implements OnItemSelectedListener {
    private final Spinner spinner;

    private int lastPosition = -1;
    private OnItemSelectedListener proxiedItemSelectedListener = null;

    public SpinnerHelper(Object spinner) {
         this.spinner = (spinner != null) ? (Spinner)spinner : null;
    }

    public Spinner getSpinner() {
        return spinner;
    }

    public void setSelection(int position) {
        lastPosition = Math.max(-1, position);
        spinner.setSelection(position);
    }

    public void setSelection(int position, boolean animate) {
        lastPosition = Math.max(-1, position);
        spinner.setSelection(position, animate);
    }

    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
        proxiedItemSelectedListener = listener;
        spinner.setOnItemSelectedListener(listener == null ? null : this);
    }

    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        if (position != lastPosition) {
            lastPosition = position;
            if (proxiedItemSelectedListener != null) {
                proxiedItemSelectedListener.onItemSelected(
                        parent, view, position, id
                );
            }
        }
    }

    public void onNothingSelected(AdapterView<?> parent) {
        if (-1 != lastPosition) {
            lastPosition = -1;
            if (proxiedItemSelectedListener != null) {
                proxiedItemSelectedListener.onNothingSelected(
                        parent
                );
            }
        }
    }

    public void setAdapter(SpinnerAdapter adapter) {
        if (adapter.getCount() > 0) {
            lastPosition = 0;
        }
        spinner.setAdapter(adapter);
    }

    public SpinnerAdapter getAdapter() { return spinner.getAdapter(); }
    public int getCount() { return spinner.getCount(); }
    public Object getItemAtPosition(int position) { return spinner.getItemAtPosition(position); }
    public long getItemIdAtPosition(int position) { return spinner.getItemIdAtPosition(position); }
    public Object getSelectedItem() { return spinner.getSelectedItem(); }
    public long getSelectedItemId() { return spinner.getSelectedItemId(); }
    public int getSelectedItemPosition() { return spinner.getSelectedItemPosition(); }
    public void setEnabled(boolean enabled) { spinner.setEnabled(enabled); }
    public boolean isEnabled() { return spinner.isEnabled(); }
}


답변

원치 않을 때 스피너 발사와 관련된 많은 문제가 있었으며 여기에있는 모든 대답은 신뢰할 수 없습니다. 그들은 때때로 작동합니다. 결국 시나리오가 실패하고 코드에 버그가 생길 수 있습니다.

나를 위해 일한 것은 마지막으로 선택한 인덱스를 변수에 저장하고 리스너에서 평가하는 것이 었습니다. 새로 선택한 색인과 동일한 경우 아무 것도 수행하지 않고 리스너를 계속하십시오. 이 작업을 수행:

//Declare a int member variable and initialize to 0 (at the top of your class)
private int mLastSpinnerPosition = 0;

//then evaluate it in your listener
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {

  if(mLastSpinnerPosition == i){
        return; //do nothing
  }

  mLastSpinnerPosition = i;
  //do the rest of your code now

}

내가 이것을 말할 때 나를 믿어 라. 이것은 지금까지 가장 신뢰할만한 해결책이다. 해킹이지만 작동합니다!


답변

나는 비슷한 상황에 있었고, 나를 위해 일하는 간단한 해결책이 있습니다.

이 방법처럼 보인다 setSelection(int position)setSelected(int position, boolean animate)다른 내부 구현이있다.

setSelected(int position, boolean animate)false 애니메이션 플래그와 함께 두 번째 방법을 사용하면 onItemSelected리스너를 시작 하지 않고 선택을 얻을 수 있습니다.