티스토리 뷰
BaseAdapter 이란 무엇일까?
기존에 디바이스에 Content내용만 다르고 Layout이 동일한 View를 여러개 표현할 경우 ScrollView를 사용할 수 있었다. 그러나, 스크롤이 보이지 않을 자식 View까지 미리 그려두기 때문에 메모리 사용량이 증가하고, LinearLayout으로 무수한 View를 배치하게되면 시스템 성능을 저하시킬 수 있다.
이러한 부분을 해결하기 위해 나온 것이 Adapter View이다.
- 콘텐츠의 내용만 다르고, 동일한 Layout들이 수직으로 그룹을 구성한 리스트
- 현재 화면에 보이지 않는 자식 뷰를 미리 생성하지 않고 스크롤되어 보여야할 때 생성
- 유사한 성격의 콘텐츠를 리스트로 배치할 때 사용
위 그림에서 보듯이 ListView를 구성하고 해당 ListView에 BaseAdapter를 연결해 사용하게 된다.
구현 코드
- List View에 보여줄 데이터를 준비한다.
- BaseAdapter 클래스를 상속받아 Adapter를 만든다.
- BaseAdapter 객체를 ListView 뷰 그룹에 연결한다.
- 화면에 List의 내용을 표현한다.
public class Student {
String mName = "";
String mNumber = "";
String mDepartment = "";
}
public class MainActivity extends Activity {
ArrayList<Student> mData = null;
protected void onCreate(Bundle savedInstanceState) {
// .....
mData = new ArrayList<Student>();
for(int i=0; i<100; ++i) {
Student stu = new Student();
stu.mName = "ch4njun" + i;
stu.mNumber = "20157260" + i;
stu.mDepartment = "컴소" + i;
mData.add(stu);
}
}
}
public class BaseAdapterEx extends BaseAdapter {
ArrayList<Student> mData = null;
Context mContext = null;
LayoutInflater mLayoutInflater = null;
public BaseAdapterEx(Context context, ArrayList<Student> data) {
mContext = context;
mData = data;
mLayoutInflater = LayoutInflater.from(mContext);
}
public int getCount() {
return mData.count();
}
public long getItemId(int position) {
return position;
}
public Student getItem(int position) {
return mData.get(position);
}
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
}
BaseAdapterEx라는 BaseAdapter 클래스를 만들고, 반드시 getView 함수를 Overrding해줘야 한다.
반복해서 표현하고 싶은 Layout을 구현한다. (이름을 list_view_item_layout.xml 이라고 가정한다.)
getView 함수는 각 위치에 맞는 Layout(정보가 포함된)를 반환해주고 그걸 List View에 제때제때 할당해주게 된다. 해당 위치가 필요할 때만 getView가 호출되기 때문에 기존 Scroll을 사용할 때의 한계를 개선할 수 있다.
public View getView(int position, View convertView, ViewGroup parent) {
// 결국 객체를 생성해서 반환해주는 거다.
View itemLayout = mLayoutInflater.inflate(R.layout.list_view_item_layout, null);
TextView nameTv = (TextView) itemLayout.findViewById(R.id.name_text);
TextView numberTv = (TextView) itemLayout.findViewById(R.id.number_text);
TextView departmentTv = (TextView) itemLayout.findViewById(R.id.department_text);
nameTv.setText(mData.get(position).mName);
numberTv.setText(mData.get(position).mNumber);
departmentTv.setText(mData.get(position).mDepartment);
return itemLayout;
}
그러나, 이렇게 구성할 경우 스크롤을 내리고 올리는데 있어서 부드럽지 못하고 로딩시간이 껴있는 것과 같이 버벅거림 현상이 나타난다.
이유는, R.layout.list_view_item_layout을 inflate하는 과정에서 시간이 오래걸리고, 또한 findViewById를 수행하는 과정에서 시간이 오래걸리기 때문이다.
이러한 문제를 해결하기 위한 아이디어는, 어차피 화면에 보여지는 View의 갯수는 정해져있고 재활용하면 좋겠다!!! 라는 것이다. 아래 코드를 살펴보자.
class ViewHolder {
TextView mNameTv;
TextView mNumberTv;
TextView mDepartmentTv;
}
public View getView(int position, View convertView, ViewGroup parent) {
// 결국 객체를 생성해서 반환해주는 거다.
View itemLayout = null;
ViewHolder viewHolder = null;
if(convertView == null) {
itemLayout = mLayoutInflater.inflate(R.layout.list_view_item_layout, null);
viewHolder = new ViewHolder();
viewHolder.nameTv = (TextView) itemLayout.findViewById(R.id.name_text);
viewHolder.numberTv = (TextView) itemLayout.findViewById(R.id.number_text);
viewHolder.departmentTv = (TextView) itemLayout.findViewById(R.id.department_text);
itemLayout.setTag(viewHolder);
}else {
viewHolder = (ViewHolder)itemLayout.getTag();
}
viewHolder.nameTv.setText(mData.get(position).mName);
viewHolder.numberTv.setText(mData.get(position).mNumber);
viewHolder.departmentTv.setText(mData.get(position).mDepartment);
return itemLayout;
}
우선 기본적인 원리는 간단하다. 이미 해당 위치에 View가 존재한다면(재사용할 수 있다면) 두 번째 인자 convertView로 해당 View에 대한 정보가 넘어온다. 그러나, 최초 생성할 경우 null이 넘어온다.
따라서 convertView 가 null일 경우 inflate로 생성하고, ViewHolder 객체를 통해 속성을 초기화하고 setTag를 호출하면 해당 View에 ViewHolder에 있는 정보가 추가된다.
없는경우 기존에 있는 정보를 ViewHolder 객체로 불러오기 위해 getTag 함수를 호출하면 된다.
이렇게할 경우 findViewById, inflate 함수가 호출되는 횟수를 최소화해 성능을 최적화할 수 있다.
'Android > Concept' 카테고리의 다른 글
[Android] SQLite Database (0) | 2020.12.04 |
---|---|
[Android] Shared Preference (0) | 2020.12.04 |
[Android] 파일과 데이터베이스 (0) | 2020.12.01 |
[Android] Remote Bound Service (AIDL 사용) (0) | 2020.11.30 |
[Android] Local Broadcast (0) | 2020.11.29 |