[안드로이드] 사용자 정의 Adapter 만들기

Adapter는 데이터 테이블을 목록 형태로 보여주기 위해 사용되는 것으로 데이터를 다양한 형식의 리스트 형식으로 보여주기 위해서 데이터와 리스트 뷰 사이에 존재하는 객체입니다. 즉, 간단히 말해 데이터와 리스트 뷰 사이의 통신을 위한 다리 역활을 합니다.

안드로이드를 살펴보면서.. 데이터를 사용자 정의 리스트뷰 형식으로 표현하는데 있어서 매우 유연한 방식을 제공한다는 것을 알게 되었고… 이런 유연함을 위해 다소 복잡한 구조에 익숙해져 볼 생각으로 이 글을 작성하게 되었습니다.

안드로이드를 처음 접하시는 분들에게 상당히 불친절한 내용이라고 생각됩니다. 제 개인적으로는 정리 차원의 글이라는 점을 다시금 언급해 드립니다.

먼저 아래와 같은 결과를 목표로 해서 사용자 정의 Adapter 만들기에 대한 핵심 내용을 정리해 보겠습니다.


사용자 삽입 이미지
인물에 대한 사진과 이름 그리고 생일 정보를 리스트 형식으로 보여주고 있는 화면입니다. 위의 화면에 대한 레이아웃은 다음과 같습니다.

사용자 삽입 이미지
즉.. Activity의 View Content가 profilelistview.xml에 해당되며 리스트뷰를 채우는 각 항목은 profileview.xml로 정의된다는 내용입니다. 먼저 큰 레이아웃인 profilelistview.xml에 대한 코드는 다음과 같습니다.



  

단순히 레이아웃 안에 list라는 id의 ListView 위젯만을 가지고 있습니다. 그리고 다음 코드는 이 ListView 위젯 안에 담을 항목에 대한 뷰에 해당하는 profileview.xml입니다.



  
  
    
    
  

위의 코드를 도식화 하면 아래와 같습니다.

사용자 삽입 이미지
수평 정렬로 지정된 레이아웃 안에 ImageView 위젯과 TextView 위젯 2개를 가지고 있는 수직 정렬로 지정된 레이아웃에 대한 내용입니다. 이제 이렇게 UI가 정해졌으니 코드에 대해서 정리해 보겠습니다.

먼저 리스트 뷰를 채울 데이터를 나타낼 클래스인 Profile에 대한 코드입니다.

class Profile {
    private int _photo;
    private String _name;
    private String _telephone;

    public int getPhoto() {
        return _photo;
    }

    public String getName() {
        return _name;
    }

    public String getTelephone() {
        return _telephone;
    }

    public Profile(int photo, String name, String telephone) {
        _photo = photo;
        _name = name;
        _telephone = telephone;
    }
}

사진에 대한 리소스 ID값과 이름 그리고 전화번호에 대한 값을 저장하고 얻기 위한 단순한 클래스입니다.

다음으로 뷰를 화면에 표시하기 위한 Activity 클래스를 상속받은 ProfileList 클래스 입니다.

public class ProfileList extends Activity {
    private ArrayList _profiles = null;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.profilelistview);
  
        _profiles = new ArrayList();
  
        Profile p1 = new Profile(R.drawable.boa, "보아", "1986년 11월 5일");
        Profile p2 = new Profile(R.drawable.kaj, "김아중", "1982년 10월 16일");
        Profile p3 = new Profile(R.drawable.nrs, "나르샤", "1981년 12월 28일");
        Profile p4 = new Profile(R.drawable.lsy, "이수영", "1979년 4월 12일");
        Profile p5 = new Profile(R.drawable.jyj, "장윤정", "1980년 2월 16");
        Profile p6 = new Profile(R.drawable.nhh, "노현희", "1972년 8월 23일");  

        _profiles.add(p1);
        _profiles.add(p2);
        _profiles.add(p3);
        _profiles.add(p4);
        _profiles.add(p5);
        _profiles.add(p6);  

        ProfileListAdapter adapter = 
            new ProfileListAdapter(this, R.layout.profileview, _profiles);

        ListView listView = (ListView)findViewById(R.id.list);
        listView.setAdapter(adapter);
    }
}

2번 코드의 _profiles는 데이터 목록을 담고 있는 컨테이너입니다. 이 컨테이너에 데이터를 추가하는 코드가 8~22번입니다. 이 컨테이너의 데이터가 바로 리스트 뷰에 표시될 정보입니다. 이 데이터와 리스트 뷰를 연결해주기 위한 것이 바로… 24번 코드, 즉.. 이 글의 주제인 사용자 정의 Adapter인 ProfileListAdapter 입니다. 이 사용자 정의 Adapter 클래스는 BaseAdapter를 상속받습니다. 코드는 아래와 같습니다.

class ProfileListAdapter extends BaseAdapter {
    private LayoutInflater _inflater;
    private ArrayList _profiles;
    private int _layout;

    public ProfileListAdapter(Context context, int layout, 
                                        ArrayList profiles) {
        _inflater = (LayoutInflater)context.getSystemService(
                                  Context.LAYOUT_INFLATER_SERVICE);
        _profiles = profiles;
        _layout = layout;
    }

    @Override
    public int getCount() {
        return _profiles.size();
    }

    @Override
    public String getItem(int pos) {
        return _profiles.get(pos).getName();
    }
 
    @Override
    public long getItemId(int pos) {
        return pos;
    }
 
    @Override 
    public View getView(int pos, View convertView, ViewGroup parent) {
        if(convertView == null) {
            convertView = _inflater.inflate(_layout, parent, false);
        }
  
        Profile profile = _profiles.get(pos);
  
        ImageView photo = (ImageView)convertView.findViewById(R.id.photo);
        photo.setImageResource(profile.getPhoto());
  
        TextView name = (TextView)convertView.findViewById(R.id.name);
        name.setText(profile.getName());
  
        TextView telephone = (TextView)convertView.findViewById(R.id.telephone);
        telephone.setText(profile.getTelephone());
  
        return convertView;
    }
}

중요한 부분만 언급하면… Override해야할 매서드는 모두 4개로써 getCount, getItem, getItemId, getView입니다. 그리고 리스트 뷰의 항목에 대한 뷰를 생성하는 getView는 처음 호출될때 두번째 인자인 convertView가 null이며 이후 개발자가 직접 인스턴스를 생성해주면 이후 호출될때는 처음 호출될때 생성된 인스턴스가 전달되는 구조로써 인스턴스의 생성에 대한 부담을 최소화하기 위한 방안입니다.

이미 안드로이드의 사용자 정의 Adapter 만들기에 대한 내용은 여타의 다양한 개발 플랫폼에서도 사용되고 있는 구조이지만… 안드로이드를 통해 다시금 접해 봄으로써.. 이러한 구조에 익숙해져서 자신이 개발하고 있는 소프트웨어에 그 설계 구조 자체를 적용해 볼 수 있는 발전으로까지 이어가길 스스로에게 다짐해 봅니다.

“[안드로이드] 사용자 정의 Adapter 만들기”에 대한 12개의 댓글

  1. 위 페이지에 나와있는대로 똑같이 햇는데 ㅠㅠ
    The application **** (process ****) has stopped unexpectedly. Please try again. << 이란 메시지가 뜨면서 안되네요 ㅠㅠ 어떻게 해결하죠??

    1. 문제의 원인을 직접 해결하신듯합니다. 저도 확인은 않해봤지만… 생성자의 위치가 문제의 원인이라니…. 상당히 의외네요. 블로그 방문 감사합니다.

  2. 여기서 만약 보아를 길게 눌렸을때 context 메뉴가 뜨면서 타이틀에 보아가 뜨게 할수 있는 방법좀 알려주세요 ㅠ

  3. 똑같이 따라했는데 getItem 부분에 오류가나서 질문 드립니다… return _profiles.get(pos).getName(); 캔낫 리졸브 메서드라는 오류가 뜨네요,,,

    1. 이 글이 매우 오래전에 작성된 글이라, 최근의 안드로이드 API에서는 언급하신 오류를 발생시키는 API를 더 이상 지원하지 않는듯합니다.

김형준(Dip2K)에 답글 남기기 응답 취소

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다