질문 올리는 김에 오늘 찾아낸 팁 하나 올려봅니다.
데이터베이스에 있는 내용을 쿼리해서 리스트에 바인딩 할 때 SimpleCursorAdapter 를 사용하시는 건 다들 아시죠?
하지만 요 어댑터의 맹점은 모든 필드를 하나의 아이템 위젯에 밖에 연결할 수 없다는 것입니다.
cs = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cursor,
new String[] { "capital", "country" },
new int[] { android.R.id.text1, android.R.id.text2 });
이 코드는 쿼리해 받아온 cursor 에서 capital, country 필드 두개를 리스트 아이템2 기본 템플릿에 바인딩하는 코드입니다.
인터넷 어디를 뒤져봐도 Cursor 를 어댑팅하는데 요런 예제밖에 없더라구요.
제가 하려는 것은 여러개의 필드를 제 맘껏 요리 붙이고 저리 붙이고 하여 띄우는 것이었습니다.
예를 들면, capital 필드의 내용과 country 필드의 내용을 합쳐(둘다 String이므로) 일반 리스트에 표시하는 것이죠.
실제 개발 중 너무나도 흔히 있는 일일텐데 관련된 예제가 하나도 없어 삽질을 좀 했습니다.
사용법은 의외로 간단합니다.
우선 CursorAdapter 를 상속받은 커스텀 커서 어댑터 클래스를 생성합니다.
아래의 코드에선 CombiningCursorAdapter 라고 이름 붙였습니다.
public class CombiningCursorAdapter extends CursorAdapter {
public CombiningCursorAdapter(Context cntx, Cursor cursor)
{
super(cntx, cursor);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
((TextView) view).setText(cursor.getString(0) + " / " + cursor.getString(1));
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
return view.findViewById(android.R.id.text1);
}
}
이클립스에서 클래스 추가하시면 자동으로 생성자, bindView, newView 를 오버라이드 해줍니다.
생성자는 뭐 생성자구요; 나머지 두 개 메소드 부분이 조금 특이합니다.
ArrayAdapter 의 경우는 getView 를 오버라이드 해서 사용하고, 매개변수인 convertView 의 내용의 null 값을 체크해서 할당합니다만,
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if( convertView == null ) {
// view 생성
}
// bind
return super.getView(position, convertView, parent);
}
CursorAdapter 의 경우는 뷰의 생성과 바인드가 분리되어 있다고 보시면 되겠습니다.
생성은 newView 메소드, 바인드는 bindView 메소드지요.
아래는 뷰를 생성하는 newView 코드입니다.
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
return view.findViewById(android.R.id.text1);
}
이 부분이 결정적인 삽질을 하게 된 부분입니다ㅠ
일단 어떤 뷰든지 리턴하게 되면 그 리턴한 뷰를 매 아이템마다 띄워주게 되어 있습니다.
이런 복잡한 코드 대신 return new TextView(context); 이렇게 사용해도 동작은 하지요.
하지만 안드로이드에서 기본 제공하는 android.R.id.xxx 류의 기본 아이템 위젯을 사용하고 싶어 이리저리 찾아봤는데 관련 예제가 도무지 없더군요;
온갖 시도 끝에 기본 제공하는 레이아웃 android.R.layout.simple_list_item_1 을 inflater 를 이용해 inflate 해서 findViewById 를 해보니 됩니다.
어째 뷰 리소스 아이디를 이용해 뷰를 생성하는 메소드는 없는걸까요 -_-
아무튼 이 부분이 어댑팅하여 띄워줄 리스트의 아이템 뷰를 생성하는 부분입니다.
생성을 했으니 이제 바인드를 해야겠지요.
@Override
public void bindView(View view, Context context, Cursor cursor) {
((TextView) view).setText(cursor.getString(0) + " / " + cursor.getString(1));
}
간단합니다. 여기서 view 에는 아까 newView 에서 리턴한 녀석이 날아옵니다.
TextView 로 캐스트해서 setText 날려주시면 되지요.
알아서 해당 위치로 포지션이 셋팅된 cursor 가 함께 날아오므로, 포지션 걱정 없이 cursor 를 마구 갖다 써주시면 되겠습니다.
생각보다는 꽤 간단한 방법이죠?
굉장히 여러가지 방법으로 커스터마이징이 가능할 것 같습니다.
위의 예제처럼 여러 필드를 합쳐 하나로 띄운다거나,
데이터베이스에 이미지URL 이 있는 경우 ImageView 를 이용해 바로 리스트에 붙인다거나 하는 작업이 가능할 듯 합니다.
ArrayAdapter 에 관련해서는 예제가 굉장히 많은데, 실 개발시 오히려 사용빈도가 높은 CursorAdapter 의 경우엔 커스텀 어댑터 예제가 보이지 않아 한번 두드려 보았습니다.
도움되셨길 바랍니다. ㅋ