본문 바로가기
해본것/안드로이드

안드로이드 recyclerView

by kk님 2020. 1. 19.

recyclerView를 알아보기 전에 adapter을 보면,

adapter의 기능: 1.데이터를 연결 2.부모컨테이너와 연결하는 기능을 갖고 있다.

이렇게만 말하면 직접 연결하기 어려우니 예를 들어 설명해보려고 한다.

 

앞으로 설명할 listdata타입의 arrayList라고 정의한다.

ArrayList<data>list = new ArrayList<data>();

@물론 여기서 xml파일로 만들어 둘수도 있지만 다음번에 참고해보자.

adapter가 필요할까?를 생각해봤는데, 아무리 생각해도 그냥 list를 뷰와 연결하면 되지 않을까?

그런데, recyclerView를 보기 전에 ListView를 먼저 살펴보면서 adapter에도 종류가 있었다.

예를들어, ArrayAdapter, CursorAdapter, SimpleAdapter가 있는데, 여기서는 ArrayAdapter에 대해 살펴보기로 하자.

ArrayAdapter(Context context, int resourceId, T[] objects)

파라미터를 살펴보면 순서대로 현재 컨택스트, 리소스Id, 원본 데이터(=상단의 예에서 data타입의 list를 담는다.)는 것을 알 수 있다.

여기서 눈여겨볼 것은 리소스Id인데, 어떤 값이 들어가는지에 따라 기능이 달라진다.

Simple_list_item_1 : 한 개의 텍스트뷰 사용

Simple_list_item_2 : 두 개의 텍스트뷰 사용

Simple_list_item_checked : 항목당 체크 표시

Simple_list_item_single_choice : 한 개의 항목만 선택 가능

Simple_list_item_multiple_choice : 여러 개의 항목선택 가능

데이터를 직접 뷰와 연결한다고 하더라도 adapter의 이런 기능들(단순 사용,체크표시,선택가능)을 추가적으로 사용하기 위해서 adapter가 필요했던 것이 아니었을까

그래서 리스트뷰를 만드는 순서는 다음과 같다.

1.     원본 데이터를 만든다.

2.     어댑터 생성 (여기서 어떤 기능을 포함할지 인자로 넣어주고 list를 인자로 포함시켜서 어댑터와 원본 데이터(=list)를 연결한다고 표현)

3.     리스트뷰를 사용할 것인데, 자바 코드로 그것을 알려야 하기 때문에, 리스트뷰 객체를 만들어줘야 한다. , ListView listview =(ListView) findViewById(R.id.ListView) xml의 리스트뷰를 findViewById를 이용해서 ListView객체를 만들어 대응시킨다.

4.     그리고 리스트뷰에 어떤 원본데이터가 필요한지 알려주기 위해, 리스트뷰에 adapter를 연결해준다.(어댑터의 인자로 list를 담고있기 때문) listview.setAdapter(adapter)

 

Inflate ?

Inflaterxml안의 여러 위젯들을 LayoutInflater 객체를 이용해서 inflate하면 메모리에 객체화되어 저장된다는 것을 의미하는데,

여기서 여러 위젯이란 xml에서 만든(만들어뒀다면) button, imageview등을 의미하고,

inflate하면 메모리에 객체화되어 저장된다는 것은 xml에 있는 것을 몽땅 하나의 객체로 만들어버리는것이 아니라, 그 뷰그룹(=부모컨테이너) 안에 있는 위젯(버튼/이미지 등)을 각각의 객체로 만드는 것(=객체 참조)을 가능하게 만든다는 것을 뜻하는 것 같다.

실제로 사용하는 예를 본다면

LayoutInflater inflater = (LatoutInflater) context.getSystem.(Context.LAYOUT_INFLATER_SERVICE);

inflater.inflate(R.layout.listlayout,this,true);

 

myImage = (ImageView)findViewById(R.id.imageItem);

myImage.setImageDrawable(aItem.getItem());

 

myText = (TextView) findViewById(R.id.dataItem);

myText.setText(aItem.getData(0));

 

inflater 객체를 생성한 후, inflater.inflatelistlayout(=xml파일 이름)inflate 한다.

이제는 inflate했기 때문에 각 위젯(여기서는 이미지뷰와 텍스트뷰)객체로 만들 준비가 되었기 때문에 다음줄에서 findViewById로 각 리소스를 찾아 객체화 한다.

 

하지만 listview는 이렇게 findViewById가 많아서 시간이 소모된다고 한다.

 

그래서 그에 따라 뷰를 재활용하는 recyclerview가 등장하게 됐는데,

RecyclerviewAdapter을 상속한 경우 위에 언급한 adapter와는 조금 다른 사용법을 익혀야 한다.

Adapter : View에 데이터를 공급하는 역할을 하는 클래스(상단 내용 참조)

RecyclerViewAdapter클래스를 상속해서 사용하는데, 반드시 구현해야 하는 인터페이스 3가지가 있다.

onCreateViewHolder( ViewGroup parent, int viewType)

public void onBindViewHolder(ViewHolder holder, int position)

getItemCount()

 

하나씩 살펴보면,

 

1.     onCreateViewHolder( ViewGroup parent, int viewType) : View를 만들고 View를 관리하기 위해 ViewHolder를 생성한다. 그리고 생성된 ViewHolderonBindViewHolder에 넘겨준다. 그리고 항목들에 대한 뷰홀더 객체들을 만들고 각 뷰홀더를 통해 항목들의 레이아웃들을 만든다.

 

……

뷰와 뷰홀더 굉장히 말이 헷갈리고 뷰가 뭐고 뷰홀더는 뭔지 너무 복잡했다.

하단의 기본적인 틀을 살펴본다면 이해가 되겠지만 쉽게 풀어보면

1)     View를 만들고 View를 관리하기 위해 ViewHolder를 생성한다.

View = 위젯. 예를들어 텍스트뷰, 이미지뷰 등의 위젯을 의미한다.

그리고 이런 View(위젯)을 관리하는 것은 위젯을 자바코드로 객체화 시키기 위한 작업을 의미하고, 인스턴스화 하는 것 까지를 의미한다.

, 여기까지는 ViewHolder의 기능이다. 이런 관리자 역할을 하는 ViewHolder를 만드는 것이 onCreateViewHolder인 것.

2)     그리고 생성된 ViewHolderonBindViewHolder에 넘겨준다

이 메소드의 반환형은 ViewHolder이다. 이것이 곧바로 onVindViewHolder에 넘어가게 되는 것.

3)      그리고 항목들에 대한 뷰홀더 객체들을 만들고 각 뷰홀더를 통해 항목들의 레이아웃들을 만든다.

항목들에 대한 뷰홀더 객체들을 만들고 : 1)에서 자바코드로 객체화 시키기 위한 작업을 의미하고, 인스턴스화 하는 것 까지를 의미한다고 했는데, 이것을 의미한다.

각 뷰홀더를 통해 항목들의 레이아웃들을 만든다 :

 View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);

 

2.     public void onBindViewHolder(ViewHolder holder, int position) : 스크롤이 움직일 때 호출되며 재활용 가능한 뷰가 있으면 실행되는 메소드. 뷰 홀더에 position에 있는 데이터를 넣는 작업을 수행한다. 이것을 뷰홀더에 데이터들을 바인딩한다고 한다.

holder : 주어진 위치에 있는 아이템의 내용을 표현하기 위해 업데이트가 이루어져야 하는 뷰 홀더

position : 어댑터 데이터세트에 있는 아이템의 위치

3.     getItemCount() : 아이템 개수를 반환

 

(1)   ViewHolder – MyAdapter.java

(2)   Adapter – MyAdapter.java

(3)   LayoutManager – MainActivity.java

(4)   RecyclerView - MainActivity.java

 

(1)(2)를 통해 어댑터 기능을 구현했다면,

(3)(4)MainActivity에서 만들어야 한다.

LayoutManagerorientation을 갖고 있어서 가로모드/세로모드를 지원한다.

그리고 아이템들의 뷰 형태를 선택해서 사용할 수 있다.

예를들어 GridLayoutManager, StaggeredGridLayoutManager(높이가 불규칙하고 다양한 형태의 그리드 리스트)

만약 LinearLayoutManager를 사용했다면 아래와 같은 인자를 넣어주면 된다.

RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

 

recyclerView에 어댑터와 레이아웃 관리자를 설정해줘야 한다. (RecyclerView containerView이다. 뷰그룹!)

 

MyAdapter mAdapter;

mAdapter = new MyAdapter();

recyclerView = (RecyclerView)findViewById(R.id.view);

RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

recyclerView.setLatoutManager(layoutManager);

recyclerView.serAdapter(mAdapter);

 

 

Adapter클래스의 기본적인 틀을 살펴보면 다음과 같다.

 

Public class 어댑터클래스명 extends RecyclerView.Adapter<어댑터클래스명.ViewHolder> {

 List<Data> items = new ArrayList<Data>();

 static class ViewHolder extends RecyclerView.ViewHolder{

   public ViewHolder(){

   }

   Public void setData() {

   }

}

Public void add(){

}

Public ViewHolder onCreateViewHolder(){

}

Public void onBindViewHolder(){

}

Public int getItemCount(){

}

}

 

각각의 메소드에 대한 기능을 이해해보려 했는데, 크게 뷰홀더와 관계된 것을 중심으로 먼저 생각해보기로 했다. (보라색 박스 안에 든 클래스 및 메소드)

뷰홀더란, viewhold 한다고 생각해보면, 위젯을 홀드하는 기능을 한다고 추측할수 있다.

그렇다면 뷰홀더는 위젯을 갖고 있어야 한다. 위젯을 가지려면 위젯을 객체화해서 만들어야 하는데,

static class ViewHolder extends RecyclerView.ViewHolder{

 TextView text;

 ImageView picture;

   public ViewHolder(View itemView){

    super(itemView);

    text = (TextView)itemView.findViewById(R.id.text);

    picture = (ImageView)itemView.findViewById(R.id.image);

   }

   Public void setData(Data data) {

    text.setText(Data.text);

    picture.setImageDrawable(Data.image);

   }

}

위와같이 ViewHolder 클래스 안에 텍스트뷰와 이미지뷰의 객체를 만들고

ViewHolder생성자에서 findViewById로 객체를 인스턴스화 한다.

그리고 setData를 통해 data와 객체를 연결해준다.

 

add는 데이터를 추가하는 메소드. notifyDataSetChanged()를 이용해서 변경된 내용을 보여준다.

Public void add(Data item){

  Items.add(item);

 . notifyDataSetChanged();

}

 

이렇게 뷰홀더 클래스와 어댑터의 add()를 작성했다면, 이제는 뷰 홀더를 실제로 레이아웃으로 만드는 것을 가능하게 하는 메소드인 (어댑터의 메소드) onCreateViewHolder()의 기능이 궁금해지는데, onCreateViewHolder가 있어야 하는지는 어떤 객체가 인스턴스화 되는지를 보면 알수있다.

 

Public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){

  View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);

  Return new ViewHolder(view);

}

뷰그룹(=xml파일명. 여기서는 item)의 내용들을 inflate 하게 되면 이제 xml파일 안에 있는 여러 위젯들을 객체화 해서 사용할 수 있게 된다.

(inflate하는 이유는 다시 말하면 위젯들을 객체화 할 수 있게 만들어 주는 것이었기 때문인데, 그래서 onCreateViewHolderinflate, xml파일의 위젯들이 객체화 될 수 있기 때문에, 상단의 ViewHolder의 생성자 안쪽 부분이 인스턴스화 될 수 있었던 것 같다.)

 

Public void onBindViewHolder(ViewHolder holder, int position){

  holder.setData(items.get(position));

}

Public int getItemCount(){

  Return items.size();

}

 

onBindViewHolder()position에 있는 아이템을 반영하기 위해 뷰홀더의 내용을 업데이트 해준다.

getItemCount()는 아이템 개수를 전달한다

 

다시한번 정리해보자.

순서상으로는 onCreateViewHolder 후에 ViewHolder가 맞는 것 같지만, 상단의 코드 순서상으로는 뷰홀더를 만들어준뒤에 onCreateViewHolder하기 때문에 헷갈릴수 있으므로 주의해야 한다.

Public class 어댑터클래스명 extends RecyclerView.Adapter<어댑터클래스명.ViewHolder> {

 List<data> items = new ArrayList<data>();

 static class ViewHolder extends RecyclerView.ViewHolder{

   public ViewHolder(){

   }

   Public void setData() {

   }

}

Public void add(){

}

Public ViewHolder onCreateViewHolder(){

}

Public void onBindViewHolder(){

}

Public int getItemCount(){

}

}

'해본것 > 안드로이드' 카테고리의 다른 글

안드로이드 스튜디오 단축키  (0) 2020.01.28
안드로이드 recyclerView  (0) 2020.01.24
안드로이드 3  (0) 2020.01.15
안드로이드 공부  (0) 2020.01.12
안드로이드 스튜디오를 활용한 실전 앱 만들기  (0) 2020.01.10