728x90

토이 프로젝트를 진행하면서 알게된 것들에 대해서 정리하고 이를 누군가 봄으로써 편하길 바라며 정리합니다.
이 글에선 자바 코드와 코틀린 코드를 혼용하여 사용합니다.

RecyclerView를 배우게 된다면 ListView는 거들떠 보지도 않게 된다. 그런 이유는 RecyclerView를 배우다보면 ListView의 확장판처럼 느껴지기 때문이다. 그럼으로 ListView를 알면 RecyclerView에 대해 조금 더 알기 쉽게 된다.
그래서 먼저 ListView를 알아본다

LinearLayout에 자식뷰 추가하기

List View를 추가하여 사용하고 싶다면 아래 코드와 같이 3줄로 작성하면 된다. (물론 XML로 설정 해야한다.)
서브 리스트 작성 xml은 넘어가고 현재 아래 코드에선 phone_info 레이아웃이라고 생각해두면 된다.

LinearLayout contact_linearLayout = findViewById(R.id.contact_linearLayout);
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.phone_info, contact_linearLayout, false);

 

코드의 두 번째 줄을 보면 System에 Service 객체를 요청하고 받는다.
이는 인자값에 들어가있는 Context.Layout_inflater_service란 이름으로 알 수 있듯이 레이아웃 리소스를 Inflate수 있도록 해준다.
=> Inflate가 무엇일까? 안드로이드에서 Inflate의 정의는 xml에 표기된 레이아웃들을 메모리에 객체화시키는 행동이다
간단하게 xml 레이아웃을 메모리화한다고 생각하자.

코드의 3번째 줄과 같이 View 타입의 view를 만들기 위해서 inflater객체의 inflate함수를 통해서 view를 만들 수 있다.

inflate함수에 들어가는 친구들을보면 R.layout.phone_info라는 xml을, contact_liearLayout이란 리니어레이아웃, false란 Boolean은 리니어레이아웃의 자식으로 붙일 것이냐 아니냐를 의미한다. 공식문서에서는 attachToRoot라고 한다.

정확한 정보는 아래 이미지와 같다

TextView name = view.findViewById(R.id.textView_name);
name.setText(data.getStringExtra("name"));
TextView number = view.findViewById(R.id.textView_phone_number);
number.setText(data.getStringExtra("number"));

만든 View에 대한 정보 추가는 위 코드와 같이 할 수있다.

우리가 만든 Infalter에 infalte명령을 내릴 때 false인자를 넣어주었다. 이는 attachToRoot에 해당하며 root View에 추가하지 않는다를 의미한다. --> 우리가 infalte한 View는 메모리에 올라가 있지만 ListView에 추가되어 있지 않다.

그럼으로 우리가 메모리에 있는 View를 ListView에 붙여줘야한다. 이에 해당하는 함수는 addView이다. 이 함수는 ViewGroup에 있는 함수이다. 우리는 현재 LiearLayout에 추가할 것이므로 아래 코드와 같이 작성한다.

contact_linearLayout.addView(vi);

addView에 대한 공식문서는 ViewGroup 페이지를 통해 할 수 있다.

developer.android.com/reference/android/view/ViewGroup#addView(android.view.View,%20android.view.ViewGroup.LayoutParams)

 

ViewGroup  |  Android 개발자  |  Android Developers

 

developer.android.com

이정도로 ListView를 커스텀하여 사용할 수 있다. Adapter로 사용하는 방법도 존재하지만 이는 설명하지않고 넘어간다.


RecyclerView 기본 구조

RecyclerView는 무조건 adapter를 이용하여 정보를 다룬다. 아직 adapter에 대해서 모른다면, 위키 정보를 읽어보면 조금 머리가 상쾌해질 것이다.

간단하게 결합도구?라고 생각해본다. 뭘 결합할까? -> 정보와 View와 결합해준다.
RecyclerView는 Adapter를 통해서 우리가 사용할 정보를 자식 View에 설정하여 추가한다. 그럼으로 adapter를 수행할 클래스를 하나 만들어줘야한다.
아래 adapter클래스 코드에서 볼 수 있듯이 17번째 줄 생성자를 통해서 List(array)를 adapter 내부에 가지고 있다.
코틀린에서는 생성자를 저렇게 적어줄 수 있다.
그리고 총 기본적인 3가지의 함수, 1개의 클래스가 필요한데 onCreateViewHolder, onBindViewHolder, getItemCount, Holder클래스다. 이름따라 생각하면 쉽다. 먼저 2개의 함수에 ViewHolder란 말이 붙어있음으로 ViewHolder부터 알아보자.

RecyclerView는 ViewHolder라는 패턴을 강제적으로 지키고 있기 때문에 ViewHolder가 필요하다
그렇기 때문에 inner class로 Holder란 클래스를 만들었고 RecyclerView의 ViewHolder를 상속받아 사용한다.
=> ViewHolder가 무엇인지 모를 수도 있다. findViewById란 함수는 View 계층에 따라 함수가 계속 반복되어 찾아서 느리다고 한다. <!-- 비용이 비싸다란 표현이 더 정확한 것 같다. --> 그래서 안드로이드에서 View Holder를 사용한다. 
이 ViewHolder에 대한 내용은 정확하지 않음으로 조금 더 신뢰할 수 있는 내용을 찾아 이해하길 바란다.
중요한 사실은 RecyclerView는 ViewHolder패턴을 강제적으로 지키기 때문에 ViewHolder 클래스를 inner class로 만들어 사용하고 있다는 것이다.

이제 adapter에 존재하는 첫번째 함수 onCreteViewHolder를 보면 ListView에서 알아보았던 것과 비슷한 것이 있다 아니 똑같은 것이 존재한다. 이제 하나씩 살펴본다.

from은 context를 받아 LayoutInflater를 반환하고 이를 가지고 infalte함수를 통해서 ListView와 같이 한다.
혼동할만한 요소는 parent이다. from함수로 넘겨준 값은 parent.context로 ViewGroup의 context를 가져온다.
ListView에서는 Context로 하였다. RecyclerView는 Activity에 존재하고 이는 parent의 ViewGroup이라고 생각할 수 있다.
onCreateViewHolder에서 결과적으로 ListView처럼 View를 만들고 Holder에 View를 넣어 Holder객체를 반환한다.
return 부분에서 새로 만든 Holder 객체는 위 코드 아래에 있는 inner class holder다.

LayoutInflater에서 쓰이는 from함수

번째 onBindViewHolder함수에서는 holder를 받는다. 무슨 Holder? 첫번째 함수에서 만든 holder다.
여기서 bind를 하는 건데 =>
bind가 뭘까? 연결해준다 정도로 간단하게 생각하고 익숙해져보자.

onBindViewHolder함수에서는 우리가 가진 정보를 ViewHolder(클래스)에서 만들어둔 View에 붙일 것이다.

Holder클래스에서 var collegeText: TextView = itemView.findViewById(R.id.CollegeName) 와 같이 변수에 xml를 연결시켜준다. 그리고 onBindVidwHolder 함수에서 holder란 인자를 이용하여 값을 지정할 수 있다.

여기서 한번 더 생각해볼 수 있는 것은 inner class holder의 ItemView다. 이 클래스의 ItemView는 무엇을 의미할까?
이는 onCreateViewHolder에서 만들었던 view를 의미한다. 즉, holder 클래스의 itemview는 onCreateViewHolder에서 만든 view를 의미하며 이 view는 현재 lsit_item_filter_college란 xml에서 만든 view들을 findViewById로 찾을 수 있게 된다.

20번째 줄에서 만든 View(현재 2번째줄)가 holder클래스 내에 있는 ItemView를 의미한다.


RecyclerView 클릭 구현

안드로이드에서 평소 클릭 구현은 어떻게할까? 쉽게 findViewById()를 통해서 xml가 연결하고 setOnClickListener 함수를 통해서 클릭 함수를 구현해왔다.

RecyclerView라고 다르게 구현할까? 같은 View이기때문에 동일하게 구현하면 된다.
하지만 기존과 다른 것은 어디에서 클릭 함수를 구현해야는지 모른다는 것이다.

차근 차근 생각해보자

0. Q: 클릭 리스너 함수를 어디서 구현할까?
    A: View에 구현할 수 있다.

1. 먼저 클릭 리스너는 View에서 사용가능하다. 그럼으로 View가 있는 곳에서 가능하다.
    Q: adapter내의 View가 어디에 존재할까?
    A: onCreateViwHolder에서의 view, holder클래스의 itemView, onBindViewHolder의 holder 객체 속 itemview가 존재한다.

2: Q: 어느 곳에서 클릭 리스너를 구현할까?
    A: onCreateViewHolder?, onBindViewHolder?, holder 클래스?

이렇게 구현할 수 있는 곳은 3가지로 어느 곳에서 작성하면 좋을지 모르겠다.
왜 모를까? 우리는 아직 각 함수내에서 진행되는 방식을 모르기때문이다. 그렇다면 내가 원하는 기능을 구현하기 위해서, 먼저 각 함수들이 무슨 일을 하는지 알아봐야한다.

 

 

그렇기 때문에 다음 글에선 각 함수에서 하는 일이 무엇이고, 어느 곳에서 클릭 함수가 진행되어야하는지 알아본다.
또한 두개의 RecyclerView를 활용하는 방법도 생각해본다.

참고:
Infalte: https://soo0100.tistory.com/1017[Thank you for everything in the world]
RecyclerView: wooooooak.github.io/android/2019/03/28/recycler_view/

반응형

+ Recent posts