본문 바로가기

TIL

[TIL] RecyclerView

[오늘 배운 내용]

-1- 메모리 구조, 스택

  • 오늘 Fragment에 간단하게 배우다가 addToBackStack() 함수보아 Stack에 대해 궁금해져서 찾아보았다.
  • 가벼운 궁금증이었는데, 내용이 너무 방대해서 가볍게만 읽어보았다
    • kotlin은 JVM에 기반하여서 JVM의 메모리 사용 방식을 따른다고 한다.
    • 프로그램 실행 시,  프로그램과 저장장치에 있던 내용들이 메모리에 로드된다. 이 프로그램의 실행을 위한 다양한 메모리 공간이 나뉘어져 있다.
    • 코드(code)실행 영역
      • 메모리의 코드 영역은 실행할 프로그램의 코드가 저장되는 영역으로 텍스트 영역이라고도 부른다. CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리하게 된다.
    • 데이터(data)영역 ( = static)
      • 패키지나 클래스 정보 등 프로그램의 전역 변수와 정적(static) 변수가 저장되는 영역이다.
      • 패키지나 클래스는 프로그램 시작과 동시에 모두 로드되는 것이 아니라, 실제 호출될 때 로드된다.
      • 해당 영역에 자리잡게되면 JVM이 종료될 때 까지 사라지지 않고, 프로그램이 종료되면 소멸된다.
    • 스택(stack) 영역
      • 지역 변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값 등이 저장되는 영역
      • 여는 중괄호 ' { ' 를 만날 때 마다 스택 프레임이 쌓이고, 닫는 중괄호 ' } ' 에 스택 프레임이 사라진다.
      • 외부 스택 프레임에서는 내부 스택 프레임의 변수에 접근하는 것은 불가능하나 그 반대는 가능하다.
      • 스레드도 stack 영역에 생긴다.
    • 힙(heap) 영역
      • 생성된 객체(instance)들이 올라간다
      • 인스턴스 필드들은 heap 영역에 올라가는데, 이런 것들이 정적인 메소드에서 인스턴스 멤버를 접근할 수 없는 이유가 된다. 메모리에 저장하는 영역이 서로 다르므로 어떤 인스턴스인지, 존재하는지 여부를 알 수 없다.
      • 상속을 이용한 인스턴스를 만들었다면 상위 클래스의 인스턴스들도 같이 생성된다 (최상위 Object까지)

 

 


-2- RecyclerView

  • RecyclerView를 사용하는 이유
    • ListView는 데이터에 있는 모든 데이터에 대한 View를 만들고, 스크롤을 통해 표시하는 Item 이 달라지면 View가 사라졌다가 다시 나타날 때마다 리소스를 불러와야 한다. 이 방법은 많은 메모리와 저장 공간을 사용하므로, 대용량의 데이터를 이용하면 앱이 느려지거나 충돌할 가능성이 높다.
    • RecyclerView는 ListView의 단점을 보완하기 위해 만들어졌다. 사용자가 스크롤을 하였을 때, View에서 사라지게 되는 아이템은 재활용이 되어서 새로 보여지는 쪽으로 이동하여 재사용 된다. 즉 보여지는 View가 10개면, 아이템이 100개가 된다고 해도 10개 정도의 View를 만들고 재사용해서 사용한다. 이 때문에 앱에서 불필요하게 메모리를 사용하는 일은 줄어들었다.
    • RecyclerView 
      • ListView와 마찬가지로 Adapter를 이용하지만, RecyclerView는 ViewHolder를 필수적으로 사용해야 하고 LayoutManager를 설정하며 ItemAnimation, ItemDecoration 
        • ViewHolder?
          • 각 항목의 뷰를 재활용하기 위해 보관하는 클래스
        • LayoutManager?
          • 목록을 어떻게 배치할지 정하는 클래스
        • Adapter
          • Item 데이터와 View를 결합시켜주는 것
        • ItemAnimation?
          • 아이템 추가, 삭제 애니메이션을 적용
        • ItemDecoration
          • ListView의 구분선(divider)은 자동으로 넣어주지만 recylcer뷰는 자동으로 구분선을 넣어주지 않아ItemDecoration으로 구분선 등 아이템을 설정한다.

 

 

RecyclerView 적용하기 루틴

  • 1. 프로젝트 기본 설정 (ViewBinding설정 및 이미지 drawable 추가 등)

 

 

  • 2. item이 보여지는 itemView 생성하기
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="70dp"
    android:layout_margin="5dp"
    android:layout_marginBottom="5dp"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/light_grey"
        android:orientation="horizontal"
        android:padding="5dp">

        <ImageView
            android:id="@+id/img_view_icon"
            android:layout_width="40dp"
            android:layout_height="60dp"
            android:layout_gravity="center" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:background="@color/light_grey"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_item_name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/grey"
                android:paddingStart="10dp"
                android:paddingTop="3dp"
                android:paddingBottom="3dp"
                android:textColor="@color/black"
                android:textSize="17sp"
                android:textStyle="bold"

                />

            <TextView
                android:id="@+id/tv_item_desc"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:background="@color/grey"
                android:paddingStart="10dp"
                android:textColor="@color/dark_grey"
                android:textSize="14sp"
                android:textStyle="bold" />

        </LinearLayout>
    </LinearLayout>
</LinearLayout>

 

 

 

  • 3. 리스트가 보여지는 Activity에 RecyclerView 생성 후 layoutManager 이용해 ⑵에서 생성해둔 itemView와 연동하기
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    >

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_list_brand"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="80dp"
        android:layout_marginBottom="160dp"

        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:listitem="@layout/item_view">


    </androidx.recyclerview.widget.RecyclerView>

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

  • 4. 리스트에 들어갈 값을 저장하는 data class 만들기
    • position의 위치에 이미지를 띄우기 위해 mImage을 정수형으로 지정. 
data class BrandData(
    var mImage : Int,
    var mName : String,
    val mDesc: String,
)

 

 

 

  • 5. ViewHolder 만들기
// (binding:ItemViewBinding) ⑵에서 생성한 itemViewBinding 하는것
class ViewHolder(binding: ItemViewBinding) : RecyclerView.ViewHolder(binding.root) {
    val iconIamgeView = binding.imgViewIcon
    val name = binding.tvItemName
    val desc = binding.tvItemDesc
}

 

 

 

  • 6. RecyclerViewAdapter 만들기
    • 6-1 ItemClick 인터페이스 만들기
    • 6-2 ⑹에서 상속받은 RecyclerView.Adapter의 메소드를 재정의 한다(getItemCount(), onBindViewHolder(), onCreateViewHolder(), getItemId 등) 나열한 메소드 중 먼저 나열한 3가지는 필수로 재정의 해야한다.
      ┗ (RecyclerView를 생성할 때 ViewHolder객체를 만들고나서 뷰에 데이터를 설정한 경우)
class RecyclerViewAdapter(private val mItems: MutableList<BrandData>) :
    RecyclerView.Adapter<ViewHolder>() {

    interface ItemClick {
        fun onClick(view: View, position: Int)
    }

    var itemClick: ItemClick? = null

    override fun getItemCount(): Int {
        return mItems.size
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.itemView.setOnClickListener {
            itemClick?.onClick(it, position)
        }
        holder.iconIamgeView.setImageResource(mItems[position].mImage)
        holder.name.text = mItems[position].mName
        holder.desc.text = mItems[position].mDesc
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemViewBinding.inflate(LayoutInflater.from(parent.context),parent, false)
        return ViewHolder(binding)
    }
}
  • onCreateViewHolder() - RecyclerView의 item의 VIew를 갖고 있는 ViewHolder 인스턴스를 생성하는 역할을 한다.
    • 프로퍼티 설명
      • parent : 새 뷰가 추가될 ViewGroup이다. (일반적으로는 RecyclerView 자체.)
      • viewType : RecyclerView에 여러 보기 유형(머리글,바닥글,일반 항목)이 있는 경우 다양한 보기 유형을 구변하는 데 사용할 수 있는 정수 값



        .
  • onBindViewHolder() - ViewHolders가 보유한 뷰에 데이터를 바인딩하는 역할

 

 

  • 7. 메인 액티비티에서 ⑷에서 생성해둔 data class의 형식으로 View에 보여줄 항목들을 작성한다
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val brandList = mutableListOf<BrandData>()
        brandList.add(BrandData(R.drawable.adererror,"Ader Error","의류"))
        brandList.add(BrandData(R.drawable.cavempt,"CavEmpt","의류"))
   }
}

 

 

 

  • 8. 메인 액티비티에서 RecyclerView와 Adapter를 연결한다
    • ⑺에서 생성해둔 list를 적용시키며, ⑶에서 생성해둔 layoutManager로 목록 배치를 적용시킴.
	val myAdapter = RecyclerViewAdapter(brandList)
        binding.recyclerListBrand.adapter = myAdapter
        binding.recyclerListBrand.layoutManager = LinearLayoutManager(this)

 

 

 

  • 9. View 클릭 시 토스트 메시지 출력 이벤트 추가.
    • ⑹-⑴ 에서 생성해둔 ItemClick 인터페이스로 클릭 이벤트 생성.
myAdapter.itemClick = object : RecyclerViewAdapter.ItemClick{
            override fun onClick(view: View, position: Int) {
                val name : String = brandList[position].mName
                Toast.makeText(this@MainActivity,"${name} 선택!",Toast.LENGTH_SHORT).show()
            }

 

 

 

 

-3- 상태 바(Status Bar) 색상 변경 및 상태 바 아이콘 색상 변경

  • 앱 내의 상단에 네트워크 환경( Wifi, 5G, LTE )과 배터리용량과 시간 및 알람 등이 표시되는 곳이 상태바인데, 새 프로젝트 생성시 기본 색상이 굉장히 마음에 안든다. 앱 내의 어떤 색으로 조합을 해도 보라보라한 느낌이 거북하다
  • 기본 상태바 색상

 

 

 

  • 상태 바 색상 바꾸기
    • app/res/values/themes.xml 에 해당코드 작성
<item name="android:statusBarColor">@color/컬러값</item>

style 내부에 적어주면 된다.

    • 상태 바 아이콘 색상 테마 변경
      • boolean 값으로 밝은 색상 아이콘, 어두운 색상 아이콘 설정 가능
<item name="android:windowLightStatusBar">false</item>

 

false - 흰색 상태 바 아이콘

 

true - 어두운 색 상태 바 아이콘

 


 

[오늘 복습한 내용]

1. 프로그래머스 코딩테스트 입문 369 게임

 

  • 작성코드
fun main() {
    fun game369(order:Int):Int{
        val numList = order.toString().split("")
        var answer = 0
        for (i in numList.indices){
            if (numList[i] != "" && numList[i] == "3" || numList[i] == "6" || numList[i]=="9"){
                answer +=1
            }
        }
        return answer
    }
}

 

 


[오류,에러 등등]

1.  오류 해결하는 대로 다음 학습 하기 급급해서 오류 정리를 못 했다

 


[느낀 점]

1. 시간이 부족한 느낌 조바심이 자꾸 든다

 

2. 전에는 오전 10~13시, 점심먹고 난 2시 ~ 3 시 시간대에 집중을 100% 하지 못했었는데, 최근 그 시간에 알고리즘 문제를 푸니까 두뇌 스트레칭 되어 그 이후에 집중이 잘 된다는 느낌을 받았다. 꾸준히 아침시간엔 알고리즘 문제를 시도해 봐야겠다

 

3. 남이 어려운 건 나도 어렵고 내가 어려운 건 남도 어렵다

 

 


[Reference]

 

 

https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.ViewHolder

https://todaycode.tistory.com/131

https://velog.io/@chris_seed/AndroidKotlin-RecyclerView%EC%9D%98-%EB%AA%A8%EB%93%A0%EA%B2%83-%EA%B8%B0%EB%B3%B8-%EC%82%AC%EC%9A%A9%EB%B2%95

https://parkho79.tistory.com/157

https://notepad96.tistory.com/191