A-B-C-D 와 같은 다양한 데이터가 혼재되어 있는 리스트뷰에서
필요할 때 각 형태의 데이터 별로 필터링 해서 보여주고 싶은 경우가 있습니다.
아래와 같은 경우죠
이럴 때 초급자들이 대개 사용하는 방법은 A 라는 데이터만 새로 만들어서 아답터에 새롭게 데이터를 넣는 것입니다.
하지만 이러한 방식이 만약 데이터베이스와 결합되게 되면 빈번한 I/O 를 유발하는 데다가
의도치 않게 많은 객체를 생성하게 되므로 성능상이나 메모리상에 그다지 좋지 않는 모양새를 나타내게 됩니다.
그래서 필요한 것이 바로! Override 를 활용한 아답터에 자체적인 필터링 기능을 붙여 넣는 것입니다.
A-B-C-D 가 조합된 리스트를 가지고 있다가 필요할 때에만 전체 리스트에서 A 데이터만 보여주는 방식인거죠
아래 예시는
남자 - 여자 라는 아이템을 동시 가지고 있을 때 필요시에 남자만 또는 여자만 보여주는 필터 기능을 붙여봤습니다.
거두 절미하고 바로 소스부터 시작하도록 하겠습니다.
(UML 이니 하는건 회사에서 업무상 하는 것만으로도 충분하니 생략 -ㅅ- 하겠습니다)
우선 아답터의 소스입니다.
package com.nobrain.flteradapter; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; public class HumanFilterAdapter extends BaseAdapter { public final static int ALL = 0; public final static int FEMAIL = 1; public final static int MAIL = 2; private int type; private List<Human> mList; private Context mContext; public HumanFilterAdapter(Context mContext) { this.mContext = mContext; mList = new ArrayList<Human>(); } public void insertHuman(Human item){ mList.add(item); } public void remove(int position){ mList.remove(position); } @Override public int getCount() { int size = 0; int fullSize = mList.size(); //필터 타입별 보여줄 갯수 정의 switch (type){ case ALL: default: size = fullSize; break; case FEMAIL: case MAIL: Human temp; for (int i =0; i< fullSize ; i++){ temp = mList.get(i); if(temp.sex == type ){ size++; } } break; } return size; } @Override public Human getItem(int position) { Human temp; int itemIndex = 0; int fullSize = mList.size(); //타입별로 가져올 아이템 정의하기 switch (type){ case ALL: return mList.get(position); } for (int i =0; i< fullSize ; i++){ temp = mList.get(i); if(temp.sex == type ){ if(position == itemIndex ){ return temp; } itemIndex++; } } return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { TextView tv; if(convertView == null){ tv= new TextView(mContext); tv.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT, ListView.LayoutParams.WRAP_CONTENT)); tv.setTextSize(20); convertView = tv; }else{ tv = (TextView) convertView; } // 오버라이드한 메쏘드를 가져옴 Human item = getItem(position); if(item != null){ tv.setText(item.name); } return convertView; } /** * 아답터의 타입을 지정한다. * @param type 전체/남자/여자 의 값 */ public void setType(int type) { this.type = type; } }
아답터에 바인딩할 데이터를 정의합니다.
private void initApp() { mAdapter = new HumanFilterAdapter(MainActivity.this); Human item; item = new Human(); item.sex = HumanFilterAdapter.FEMAIL; item.name= "Jessy"; mAdapter.insertHuman(item); item = new Human(); item.sex = HumanFilterAdapter.MAIL; item.name= "John"; mAdapter.insertHuman(item); item = new Human(); item.sex = HumanFilterAdapter.FEMAIL; item.name= "Fukuyu"; mAdapter.insertHuman(item); item = new Human(); item.sex = HumanFilterAdapter.MAIL; item.name= "Jason"; mAdapter.insertHuman(item); item = new Human(); item.sex = HumanFilterAdapter.FEMAIL; item.name= "Fukume"; mAdapter.insertHuman(item); mListView.setAdapter(mAdapter); }
저는 별도로 리스트를 관리하지 않고 아답터에 다 위임하는 편이라 위와 같이 소스를 작성하는 편입니다.
클릭 이벤트 발생시 아래와 같이 소스가 구성됩니다.
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_type_all:
mAdapter.setType(HumanFilterAdapter.ALL);
break;
case R.id.btn_type_female:
mAdapter.setType(HumanFilterAdapter.FEMAIL);
break;
case R.id.btn_type_male:
mAdapter.setType(HumanFilterAdapter.MAIL);
break;
}
mAdapter.notifyDataSetChanged();
}
위와 같이 소스를 소스를 구성하면 아래와 같이 로직이 수행됩니다.
그러면 실행된 이미지를 봐야겠죠? ^^
그냥 짬내서 한 10분동안 요로코롬 뚝딱 만들어서 자그마한 아답터 사용법 끄적여봤습니다. :)
프로젝트 샘플은 첨부파일에 넣었으니 한번 들여다 보시기 바랍니다.
그럼..초급자분들 화이팅~^^
DB 입출력이 번번한 경우라면 CursorAdapter 를 상속받아 구현하시는 것이 나을 겁니다.
자료구조문제이지만, getCount, getItem 등의 메쏘드 호출이 내부적으로 빈번하기때문에 필터링 정보가 한정적이라면 dataset을 여러개 사용하시면서 생성자와 add, delete 등을 오버라이딩 하셔서 분리하시는 것이 속도면에서는 유리하고 메모리는 더 차지하겠죠.
한 화면에 리스트가 7개정도 보일때 setSelection(200); 하면
for문을 1400회 정도 돌고 스크롤 할때마다 수백회씩 돌텐데..
그냥 객체를 새로만드는게 낫지 않을까요 -_-?