๊ด€๋ฆฌ ๋ฉ”๋‰ด

JiYoung Dev ๐Ÿ–ฅ

[Android] RecyclerView (2023.07.20, 24) ๋ณธ๋ฌธ

full stack/์•ˆ๋“œ๋กœ์ด๋“œ

[Android] RecyclerView (2023.07.20, 24)

Shinjio 2023. 7. 20. 17:33

๋ฐ˜๋ณต๋˜๋Š” ๋ ˆ์ด์–ด

์Šคํฌ๋กค

 

 

ArrayList → ๋ฐ์ดํ„ฐ์˜ ์ˆ˜๋Ÿ‰์„ ์•Œ ์ˆ˜ ์—†์„ ๋•Œ ์‚ฌ์šฉ 

๋ฐฐ์—ด → ๋ฐฐ์—ด์˜ ํฌ๊ธฐ๊ฐ€ ๊ณ ์ •๋˜์–ด ์žˆ์„ ๋•Œ (๋ฐ์ดํ„ฐ์˜ ์ˆ˜๋Ÿ‰์ด ์ •ํ•ด์ ธ ์žˆ์„ ๋•Œ)

 

๋ฌด์กฐ๊ฑด ArrayList๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ๊ฒƒ์€ ์•„๋‹˜!

 


RecyclerView ์›๋ฆฌ

 

RecyclerView๋Š” ํ™”๋ฉด ํฌ๊ธฐ์—์„œ ์ข€๋” ์—ฌ์œ ์žˆ๊ฒŒ ๋ณต์‚ฌ ํ›„ ์Šคํฌ๋กค์„ ์˜ฌ๋ฆฌ๋ฉด view๋ฅผ ์žฌํ™œ์šฉ

→ view๋ฅผ ์žฌํ™œ์šฉํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋งŒ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์†๋„๊ฐ€ ๋น ๋ฆ„ 

 

ListView๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ 100๊ฐœ๋ฉด ํ…œํ”Œ๋ฆฟ๋„ 100๊ฐœ → ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ๋ถˆ๋Ÿฌ์˜ค๋Š” ์†๋„๊ฐ€ ๋Š๋ ค์ง

 

 

Recycler View๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ์—์„œ ๋ฆฌ์ŠคํŠธ์™€ ๊ทธ๋ฆฌ๋“œ์™€ ๊ฐ™์€ ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ํ‘œ์‹œํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ทฐ(View) ๊ทธ๋ฃน์ž…๋‹ˆ๋‹ค. ๊ธฐ์กด ListView์˜ ๋ฌธ์ œ์ ์„ ๊ฐœ์„ ํ•˜๊ณ  ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์•ˆ๋“œ๋กœ์ด๋“œ ์ง€์› ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

Recycler View์˜ ์ฃผ์š” ์›๋ฆฌ
์žฌํ™œ์šฉ(Recycling):
Recycler View๋Š” ๊ทธ ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด "์žฌํ™œ์šฉ"์„ ์ค‘์ ์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค(UI)์— ๋ณด์—ฌ์งˆ ๋•Œ ๋ฆฌ์ŠคํŠธ๋‚˜ ๊ทธ๋ฆฌ๋“œ์˜ ๊ฐ ์•„์ดํ…œ์„ ๋ทฐ๋กœ ํ‘œ์‹œํ•˜๊ณ , ์Šคํฌ๋กค๋ง์— ๋”ฐ๋ผ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ์•„์ดํ…œ๋“ค์ด ๋Š์ž„์—†์ด ์žฌ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, ํ™”๋ฉด์— ๋ณด์—ฌ์ง€๋Š” ์•„์ดํ…œ ์ค‘ ํ•˜๋‚˜๊ฐ€ ์Šคํฌ๋กค๋˜์–ด ํ™”๋ฉด์„ ๋ฒ—์–ด๋‚˜๋ฉด ํ•ด๋‹น ๋ทฐ๋Š” ์ฆ‰์‹œ ์žฌํ™œ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ์žฌํ™œ์šฉ ๋ทฐ๊ฐ€ ๋ฆฌ์ŠคํŠธ์˜ ๋์—์„œ ๋‹ค์‹œ ๋ณด์—ฌ์ง€๋Š” ์ƒˆ๋กœ์šด ์•„์ดํ…œ์˜ ๋ฐ์ดํ„ฐ๋กœ ์—…๋ฐ์ดํŠธ๋˜์–ด ํ™”๋ฉด์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ๋ทฐ๋“ค์„ ์žฌ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ค„์–ด๋“ค๊ณ  ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

ViewHolder ํŒจํ„ด:
Recycler View๋Š” ViewHolder ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ทฐ์˜ ์žฌํ™œ์šฉ์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ViewHolder๋Š” Recycler View์—์„œ ์•„์ดํ…œ ๋ทฐ๋ฅผ ๋‹ด์•„๋‘๋Š” ๊ฐ์ฒด๋กœ, ๊ฐ ์•„์ดํ…œ ๋ทฐ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋“ค์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
RecyclerView๋Š” ์•„์ดํ…œ ๋ทฐ๋ฅผ ๋ณด์—ฌ์ค„ ๋•Œ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹ , ์ด์ „์— ์ƒ์„ฑ๋œ ViewHolder ๊ฐ์ฒด๋ฅผ ์žฌํ™œ์šฉํ•˜์—ฌ ๋ทฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด findViewById์™€ ๊ฐ™์€ ๋น„์šฉ์ด ๋“œ๋Š” ์ž‘์—…์„ ๋งค๋ฒˆ ๋ฐ˜๋ณตํ•˜์ง€ ์•Š๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋ทฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

LayoutManager:
Recycler View๋Š” ๋ทฐ๋“ค์˜ ๋ฐฐ์น˜๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” LayoutManager๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. LayoutManager๋Š” Recycler View์—๊ฒŒ ์–ด๋–ป๊ฒŒ ๋ทฐ๋“ค์„ ๋ฐฐ์น˜ํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฆฌ์ŠคํŠธ ํ˜•์‹์˜ ๊ฒฝ์šฐ์—๋Š” ์„ธ๋กœ๋กœ ์•„์ดํ…œ๋“ค์ด ๋‚˜์—ด๋˜์–ด์•ผ ํ•˜๊ณ , ๊ทธ๋ฆฌ๋“œ ํ˜•์‹์˜ ๊ฒฝ์šฐ์—๋Š” ๊ฒฉ์ž ํ˜•ํƒœ๋กœ ๋ฐฐ์น˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. LayoutManager๋Š” ์ด๋Ÿฌํ•œ ๋ทฐ ๋ฐฐ์น˜ ๋กœ์ง์„ ๋‹ด๋‹นํ•˜์—ฌ Recycler View๊ฐ€ ํ™”๋ฉด์— ๋ณด์—ฌ์ง€๋Š” ๋ทฐ๋“ค์˜ ์œ„์น˜๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.Adapter: Recycler View๋Š” ๋ฐ์ดํ„ฐ์™€ ๋ทฐ ๊ฐ„์˜ ๋‹ค๋ฆฌ ์—ญํ• ์„ ํ•˜๋Š” Adapter๋ฅผ ํ•„์š”๋กœ ํ•ฉ๋‹ˆ๋‹ค. Adapter๋Š” Recycler View์— ํ‘œ์‹œํ•  ์•„์ดํ…œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ViewHolder๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ”์ธ๋”ฉํ•˜์—ฌ ํ™”๋ฉด์— ํ‘œ์‹œํ•  ๋ทฐ๋“ค์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์‚ฌ์šฉ์ž์˜ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฐ์ง€ํ•˜์—ฌ ์ ์ ˆํ•˜๊ฒŒ ๋ทฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์žฌํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ์›๋ฆฌ๋“ค๋กœ Recycler View๋Š” ํšจ์œจ์ ์ด๊ณ  ๋น ๋ฅธ ๋ฆฌ์ŠคํŠธ์™€ ๊ทธ๋ฆฌ๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ์•ฑ์—์„œ๋Š” Recycler View๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค.

 

 

ViewHolder ํด๋ž˜์Šค ์ƒ์„ฑ

 

 

package com.sjy.ex20230720

import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import org.w3c.dom.Text

class KakaoViewHolder(var itemView : View) : ViewHolder(itemView) {
                        //์ƒ์„ฑ์ž                ์ƒ์†
    //class KakaoViewHolder extends ViewHolder{
    //  KakaoViewHolder(View itemView){
    //      super(itemView); super -> ์ƒ์œ„ ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž ํ˜ธ์ถœ
    //   }
    // }

    //ํ…œํ”Œ๋ฆฟ์— ์žˆ๋Š” view๋ฅผ ์ €์žฅ
    var img : ImageView
    var tv_name : TextView
    var tv_message : TextView
    var tv_time : TextView

    //default ์ƒ์„ฑ์ž => ๋งค๊ฐœ๋ณ€์ˆ˜ X ์ƒ์„ฑ์ž
    init{
        //itemView => template
        img = itemView.findViewById(R.id.img)
        tv_name = itemView.findViewById(R.id.tv_name)
        tv_message = itemView.findViewById(R.id.tv_message)
        tv_time = itemView.findViewById(R.id.tv_time)
    }
}

 

 


 

Adaptor

 

 

์ƒ์†์˜ ํŠน์ง• 
1. extends
 - ์ž์‹ ํด๋ž˜์Šค๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๊ธฐ๋Šฅ(๋ฉ”์„œ๋“œ), ํ•„๋“œ๋ฅผ ๋ฌผ๋ ค๋ฐ›๋Š”๋‹ค. 
2. ~๊ณ„์—ด → ์—…์บ์ŠคํŒ…
 - ์—…์บ์ŠคํŒ… : ํ•˜์œ„ ํด๋ž˜์Šค ํƒ€์ž…์˜ ๊ฐ์ฒด๊ฐ€ ์ƒ์œ„ ํด๋ž˜์Šค ํƒ€์ž…์œผ๋กœ ํ˜•๋ณ€ํ™˜์ด ์ผ์–ด๋‚˜๋Š” ๊ฒƒ
 - ์ž์‹ํด๋ž˜์Šค๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค๋กœ ์—…์บ์ŠคํŒ…์ด ํ•ญ์ƒ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค → ๋ฆฌ์Šค์ฝ”ํ”„์น˜ํ™˜์˜ ๋ฒ•์น™(LSP)
- ๋‹ค์šด์บ์ŠคํŒ… : ์—…์บ์ŠคํŒ…๋œ ๊ฐ์ฒด๋ฅผ ๊ธฐ์กด์˜ ํ•˜์œ„ ํด๋ž˜์Šค๋กœ ๋˜๋Œ๋ฆฌ๋Š” ๊ฒƒ

** final ํ‚ค์›Œ๋“œ
1. final ํ•„๋“œ : ์ˆ˜์ •์ด ๋ถˆ๊ฐ€๋Šฅ(์ƒ์ˆ˜)
2. final ํด๋ž˜์Šค : ๋” ์ด์ƒ ์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅ
3. fianl ๋ฉ”์†Œ๋“œ : ๋” ์ด์ƒ ์˜ค๋ฒ„๋ผ์ด๋”ฉ์ด ๋ถˆ๊ฐ€๋Šฅ

 

 

 

 

package com.sjy.ex20230720

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView.Adapter

class KakaoAdapter(var context:Context, var template:Int, var data:ArrayList<KakaoVO>)
    : Adapter<KakaoViewHolder>() {
    //์ƒ์œ„ ํด๋ž˜์Šค์ธ Adapter ํด๋ž˜์Šค๋Š” ์ถ”์ƒ ํด๋ž˜์Šค
    // => ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›๋Š” ํ•˜์œ„ ํด๋ž˜์Šค๋Š” ๋ฐ˜๋“œ์‹œ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ(์žฌ์ •์˜)ํ•ด์•ผํ•œ๋‹ค.
    // => ์˜ค๋ฒ„๋ผ์ด๋”ฉ ์•ˆํ•˜๋ ค๋ฉด ์ถ”์ƒํ™”
    //adapter : templete๊ณผ data ์—ฐ๊ฒฐ (๋งค๊ฐœ๋ณ€์ˆ˜ 3๊ฐœ : ํ™”๋ฉด, ํ…œํ”Œ๋ฆฟ, ๋ฐ์ดํ„ฐ)
    //
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KakaoViewHolder {
        //templete์— ์žˆ๋Š” view๋ฅผ ์ €์žฅํ•˜๋Š” viewholoder๋ฅผ ์ƒ์„ฑ
        //ํ•˜๋‚˜์˜ ๋ฆฌ์‹ธ์ดํด๋Ÿฌ๋ทฐ์—์„œ ์ตœ์ดˆ 1๋ฒˆ๋งŒ ์‹คํ–‰ >> onBindViewHolder์—์„œ ๊พธ๋ฐˆ
        //xml => kt(java) ๊ฐ์ฒด๋กœ ๋งŒ๋“œ๋Š” ์ž‘์—…์„ Inflater๋ผ๊ณ  ๋ถ€๋ฆ„
        //๋Œ€ํ‘œ์ ์œผ๋กœ findViewById

        //ViewHolder๋ฅผ ์ƒ์„ฑํ•  ๋•Œ Templete.xml์„ Viewํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์ „๋‹ฌ
        var templete_view : View = LayoutInflater.from(context).inflate(template, parent, false)
        var VH : KakaoViewHolder = KakaoViewHolder(templete_view)

        return VH
    }

    override fun getItemCount(): Int {
        //์ „์ฒด ์•„์ดํ…œ์˜ ๊ฐœ์ˆ˜๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ๊ณณ
        //return 5 => 5๊ฐœ ๋ฐ˜ํ™˜
        return data.size
    }

    override fun onBindViewHolder(holder: KakaoViewHolder, position: Int) {
        //์ œ๋„ค๋ฆญ๊ธฐ๋ฒ• : ํด๋ž˜์Šค๋ฅผ ์„ค๊ณ„ํ•˜๋Š” ์‹œ์ ์—๋Š” ์ž๋ฃŒํ˜•์„ ๊ธฐ์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค.
        //์ด์ „์— ์“ฐ๋˜ ViewHolder์—์„œ View๋ฅผ ๊บผ๋‚ด๋‹ค๊ฐ€ ArrayList์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋“ค๋กœ ๊พธ๋ฐˆ!
        //getItemCount์— ์ ํžŒ ์ˆซ์ž๋งŒํผ ํ˜ธ์ถœ๋จ

        var img : ImageView = holder.img
        var tv_msg : TextView = holder.tv_message

        var KakaoMessage : KakaoVO = data.get(position)

        img.setImageResource(KakaoMessage.img)
        tv_msg.text = KakaoMessage.msg

        //ver2.
        holder.tv_name.text = data.get(position).name
        holder.tv_time.text = data.get(position).time
    }

}