[Android]안드로이드 콤보박스 스피너(Spinner)의 setOnItemSelectedListener()가 자동실행 문제점 해결방법
안드로이드 콤보박스 스피너(Spinner)
안드로이드에서 제공하는 스피너 위젯을 사용하여 콤보박스를 구현시 하나의 문제가 있습니다. 그것은 바로 Activity 생명주기 단계 중에 onCreate() 단계에서 setOnItemSelectedListener()가 무조건 호출 되어 onItemSelected()메소드가 자동으로 실행되는 문제가 있습니다. 여러개의 스피너를 사용하여 사용자에게 검색 조건(필터, 옵션)으로 제공시 스피너 여러개가 동시에 실행됨으로써 데이터베이스 서버에 조회 쿼리에 대한 질의를 여러번 하는 문제가 발생합니다. 또 한 스피너(Spinner) A 와 스피너 B가 있다고 했을때 스피너 B를 선택한 경우 스피너 A의 값을 초기값으로 “-전체 옵셥-“으로 변경하기 위해 spinnerA.setSelection(0) 또는 spinnerA.setSelection(0, false)를 처리하게됩니다. 그러나 setSelection()메소드를 사용해서 값을 설정하는 경우 onItemSelected()메소드가 자동호출되는 문제가 발생합니다. onItemSelected()메소드의 인자값인 adapterView 나 view를 사용하여 view.isPressed()를 호출해보았으나 모두 false로 결과가 리턴되기 때문에 문제해결을 위한 방법으로 사용할 수 없습니다.
spinnerA.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
inquerySqlite();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
spinnerB.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
inquerySqlite();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
스피너 사용시 3가지 문제점
- onCreate()시 자동 실행되는 문제점
- setSelection() 사용시 자동 실행되는 문제점
- 사용자가 스피너를 클릭하여 콤보박스 값을 변경한 경우와 setSelection()메소드를 사용하여 변경한 경우에 대한 이벤트를 구분을 할 수 없는 문제
이러한 3가지의 문제점을 해결하기위해 스피너 클릭 이벤트 spinnerA.setOnClickLIstener()메소드를 사용해보기 위해 처리해 보려고 했으나 스피너에서는 안타깝게도 지원하지 않습니다.
문제점 해결하기
1. onCreate()시 자동실행되는 문제점 해결하는 방법
스피너가 초기화 완료되었는지 여부에 대해서 판단을 할 수 있도록 전역변수를 하나 선언하여 쿼리문실행시 조건절로 사용합니다. 아래 코드 스니펫을 참고하세요.
public class MainActivity extends AppCompatActivity {
Spinner spinnerA, spinnerB;
boolean isInit = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
...위젯 초기화 부분 생략
spinnerA.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
//스피너 초기화 여부 체크 변수 체크 후 쿼리 질의 메소드 호출 처리
if(isInit) inquerySqlite();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
spinnerB.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
//스피너 초기화 여부 체크 변수 체크 후 쿼리 질의 메소드 호출 처리
if(isInit) inquerySqlite();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
//DB조회
inquerySqlite();
//초기화완료 처리
isInit = true;
}
}
또다른 방법은 setOnItemSElectedListener(listener) 리스너를 설정하기 전에 setSelection(position, false)메소드를 사용합니다. 리스너가 설정전임으로 null이기 때문에 아무것도 실행되지않게 되는 것이죠
Spinner spinnerA = findViewById(R.id.spinner);
spinnerA.setAdapter(adapter);
spinnerA.setSelection(position, false);
spinnerA.setOnItemSelectedListener(listener);
2. setSelection() 사용시 자동 실행되는 문제점 해결방법 및 사용자가 스피너를 클릭하여 콤보박스 값을 변경한 경우와 setSelection()메소드를 사용하여 변경한 경우에 대한 이벤트를 구분을 할 수 없는 문제해결 방법
스피너를 터치했을 때 스피너를 구분하는 전역변수를 하나 추가 후 사용자가 직접 터치했을 경우에만 호출하도록 조건을 주는 방법을 사용합니다. 아래 예제 코드에서처럼 spinnerA에서 사용자가 선택시 spinnerB 스피너의 선택값을 초기화해주지만 사용자가 spinnerB를 터치한 것이 아님으로 실행을 방지합니다.
public class MainActivity extends AppCompatActivity {
Spinner spinnerA, spinnerB;
int searchFilter = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
...위젯 초기화 부분 생략
spinnerA.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
spinnerB.setSelection(0, false);
//사용자가 스피너를 선택하여 변경하는 경우에만 조회되도록 변경
if(searchFilter == 1) inquerySqlite();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
spinnerB.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
spinnerA.setSelection(0, false);
if(searchFilter == 2) inquerySqlite();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
spinnerA.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
searchFilter = 1;
return false;
}
});
spinnerB.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
searchFilter = 2;
return false;
}
});
//DB조회
inquerySqlite();
//초기화완료 처리
isInit = true;
}
}
스피너의 구현 방법은 구글 개발자문서를 참고하세요.
[연관글 더 보기]
[프로그래밍/Kotlin] - [android : kotlin] 코틀린 Spinner 사용 예제( 콤보박스 )