본문 바로가기
Programming/Android

10장.AdapterView 활용

by jaegom 2020. 5. 31.

 

-Adapter와 AdapterView

-AdapterView : 항목을 나열하는 뷰, 하나의 뷰에 여러 데이터를 나열하고 그 중 하나를 사용자에게 선택받는 뷰

ex) ListView, GridView, Spinner 등이 AdapterView를 상속받아 작성된다.

어댑터뷰 상속구조

-액티비티는 button과 같은 뷰를 직접 출력할 수 있지만 AdapterView는 직접 출력하지 못한다. Adapter를 이용한다.

-Adapter : AdapterView를 만들어주는 클래스

ex)ArrayAdapter, SimpleAdapter, CursorAdapter, Custom Adapter 등

어댑터 상속구조

 

-ArrayAdapter : 각 항목에 문자열 데이터를 순서대로 하나씩 나열할 때 사용 ex) 원기날씨 지역선택 목록

ex) ListView를 ArrayAdapter를 이용하여 출력, 대표적인 나열형 뷰

//리스트뷰 생성

<ListView android:id~ android:layout_width,height~/>

//항목 데이터 구성하기

String[] datas = getResources().getStringArray(R.array.location);

//ArrayAdapter 생성 후 리스트 뷰 출력

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, datas);

//리스트뷰 출력

listView.setAdapter(adapter);

cf) 라이브러리 제공 ListView 항목 xml

simple_list_item_1 : 항목에 문자열 데이터 하나

simple_list_item_2 : 항목에 문자열 데이터 두 개 위아래 나열

simple_list_item_multiple_choice : 문자열 오른쪽에 체크박스 제공

simple_list_item_single_choice : 문자열 오른쪽에 라디오 버튼 제공

 

cf) 직접 xml을 작성해서 ArrayAdapter에 넘겨도 된다, 다만 어느 넘길 뷰의 텍스트를 정해줘야 한다.

String[] datas = getResources().getStringArray(R.array.location);

//매개변수 -> 객체, xml, xml 중 출력할 뷰의 id, 항목을 구성하는 데이터

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.main_item, R.id.main_item_name, datas);

listView.setAdapter(adapter);

*OnItemClickListener를 구현하고 setOnItemClickListener로 ListView에 리스너를 등록하면 항목 클릭 시 onItemClick 함수가 자동으로 호출된다. onItemClick의 매개변수 중 세 번째는 사용자가 선택한 항목의 index가 되시겠다.

*ListView를 adapter로 출력한 후 데이터가 동적으로 추가/제거 될 시 adapter에게 전달한 항목 집합 객체에 데이터만 추가/제거 해주면 된다. notifyDataSetChanged() 함수 사용.

 

SimpleAdapter : 한 항목에 문자열 데이터를 여러 개 나열할 때 사용 ->ListView를 SimpleAdapter로 출력 ex)카톡 대화창

-하나가 아닌 여러 문자열이므로 HashMap 객체 사용.

ex) ArrayList<HashMap<String, String>> datas = new ArrayList<>();

HashMap<String, String> map = new HashMap<>(); 

map.put("name", "류현진");

map.put("content", "화이팅");

datas.add(map);

map = new HashMap<>();

map.put("name", "오승환");

map.put("content", "이겨라");

datas.add(map); // ArrayList에 HashMap 두 개를 담았다. ArrayList를 SimpleAdapter에 적용(각 항목에 문자열이 2개 나옴)하고 이것으로 ListView를 출력.

ex)

SimpleAdapter adapter = new SimpleAdapter(this,

datas, android.R.layout.simple_list_item2,

new String[]{"name", "content"}; //HashMap 데이터 키 값

new int[]{android.R.id.text1, android.R.id.text2}); // 출력 뷰 id

listView.setAdapter(adapter);

cf) context 자리에 this를 넣는다 -> 애플리케이션 레벨에서 시스템 레벨의 기능 및 정보를 활용할 경우 context 사용.

 

CursorAdapter : 안드로이드 DBMS의 select된 결과값을 이용해 항목 구성, select 결과값이 cursor 객체이며 원래는 직접 행의 column 데이터를 추출해서 사용한다. 하지만 cursor 객체를 CursorAdapter에 넘겨주면 행의 column 데이터를 추출해서 뷰에 출력해준다.

ex)

CursorAdapter adapter = new SimpleCursorAdapter(this,

android.R.layout.simple_list_item_2, cursor,

new String[] { "name", "content"}, //데이터 추출 시 명시하는 column명

new int[] {android.R.id.text1, android.R.id.text2}, //출력 뷰 id

CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

listView.setAdapter(adapter);

 

Custom Adapter : ListView의 각 항목을 문자열 나열 이상으로 꾸미고 싶을 때 직접 만드는 어댑터, 커스텀 xml을 적용하는 것을 넘어선 상황. 대부분의 경우 해당

-사용하는 경우

1. 구글 드라이브에서 파일 종류에 따라 이미지 변환(개발자 알고리즘을 추가하고 싶을 때),

2. 항목에 나열된 뷰마다 다른 이벤트 처리를 지정

3. 항목마다 다른 layout 출력하기(SimpleAdapter 수준에서도 가능)

-작성법

1. 항목별 데이터를 추상화한 VO클래스 선언

ex)

//자료 접근을 위해 getter/setter 함수를 쓰지 않고 직접 변수에 접근(함수보다 빠르니까)

public class DriveVO {

  public String type;

  public String title;

  public String date;

}

2. Adapter 작성 - 라이브러리의 Adapter 하나 상속 받기, getCount, getView 재정의 필수(자동 호출됨)

ex)

public class DriveAdapter extends ArrayAdapter<DriveVO> {

  Context context;

  int resId;

  ArrayList<DriveVO> datas;

  //액티비티에서 넘기는 context, xml 아이디, 항목구성데이터를 생성자로 받음(한 번만 받으면 되니까)

  public DriveAdapter(Context context, int resId, ArrayList<DriveVO> datas) {

  }

  @Override

  public int getCount() {

  }

  @NonNull

  @Override

  public View getView(int position, VIew convertView, ViewGroup parent) {

  }

}

-getCount : 전체 항목의 개수 판단

-getView : 항목 하나를 구성하는 코드(전체가 아님), 반환값이 해당 항목의 View, 그러므로 해당 항목의 index 필요.

1.항목 구성을 위해 레이아웃 xml초기화(LayoutInflater) -> 2.view 획득(이미지뷰, 텍스트 뷰 등) -> 3.항목 데이터의 객체 획득(뷰를 출력할 항목 객체의 int position) -> 4.항목view의 데이터 설정(객체.title, 객체.date) -> 5. view 출력을 위한 알고리즘 설정(이미지->img.png, 텍스트 ->file.img 등 확장자 보고 알아서 출력)

ex)

 

- 커스텀 Adapter의 성능

-Adapter 레이아웃을 구성하려면 상속받은 어댑터를 초기화(LayoutInflater -> inflate() ), 구성할 때마다 초기화하면 연산 낭비니까 최초로 호출할 때만 초기화한다 -> getView의 두 번째 매개변수가 null =최초 , null이 아니면 호출이력 있음(view 객체를 반환한 이력).

ex)

-findViewById()로 최초로 뷰를 획득 후 저장해놓고 계속 사용하는 것이 연산상 이득, 대상이 되는 뷰들을 하나로 묶은 클래스를 정의(Holder 클래스) 후 Adapter가 Holder 객체 메모리를 지속시켜준다.

ex)

public class DriveHolder {

  public ImageView typeImageView;

  public ImageView menuImageView;

  public TextView titleView;

  public TextView dateView;

    public DriveHolder(View root) {

      typeImageView = root.findViewById(~);

      ~;~;~;~;

    }

}

-Adapter는 holder 객체를 getView 함수의 반환 객체에 저장하여 메모리를 지속시킬 수 있다.

ex)

DriveHolder holder = new DriveHolder(convertView);

convertView.setTag(holder); //객체 저장(뷰 객체는 원래 visible 데이터를 다루지만 non-visible 데이터도 setTag를 통해서 저장할 수 있다. setTag(value), setTag(key, value -> 여러 데이터), 데이터의 임시 저장을 view로 실현할 수 있다.

Driveholder holder = (Driveholder)convertView.getTag(); // 객체 획득 후 holder 객체의 변수를 접근.

 

 

 

 

 

 

 

 

 

 

댓글