본문 바로가기

[Android]/App UI 따라 만들기

[배달의 민족] 따라만들기 9편 (RecyclerView, ListAdapter, DIffCallback, Flexbox, Glide)

 

 

안녕하세요 허접 샴푸입니다~!

 

오랜만에 배달의 민족 따라 만들기 9편입니다!

 

이번 시간에 구현할 것은 아래 뭐 먹지 화면입니다.

물론 실제 배달의 민족 앱에서는 그림이 아닌 동영상이지만, 저는 동영상을 그림으로만 표시하였습니다.

동영상을 재생하기 위해서는 ExoPlayer을 사용해야 하는데 이는 추후에 다루도록 하겠습니다.

 

아래 화면을 구현하기 위해서는 RecyclerView + Adapter, Glide, Flexbox라고 생각됩니다.

 


[START]

1. 뭐 먹지 리스트용 Fake 데이터이며 이에 맞는 Data class를 작성합니다.

title, imageUrl, tags라는 String 변수들입니다.

 

[예 - 왼쪽 그림을 예시로...]

 

title : "캠핑한끼 리얼 까르보나라"

imageUrl : "https://" 형태의 이미지 주소

tags : "까르보나라, 파스타, 크림파스타"

 

 

 

 

 

 

 

 

 

 

2. fragment_eat_what.xml 작성

 

3. EatWhatRepository, Impl 작성

MVVM App Architecture 형태를 따르기 위해, 위에 만든 fakeWhatToEatList 리스트를 추출하기 위해 Repository 구현 클래스를 만듭니다.

suspend fun 인 이유는 간단하고 편리한 Coroutine을 이용할 것이기 때문입니다.

 

 

4. EatWhatViewModel 작성

단순하게 Encapsulation을 위해

private MutableLiveData(읽기 / 쓰기 전용)과 LiveData(읽기 전용) 두 개의 LiveData 변수를 선언합니다.

 

그리고 getFakeWhatToEatList() 함수에서는 viewModelScope(해당 viewModel이 파괴되면 자동적으로 파괴되어 매우 편리함)을 이용하여 Repository의 getWhatToEatItems()를 호출하여 MutableLiveData에 postValue 합니다.

 

postValue인 이유는 withContext(IO)의 스레드는 백그라운드 스레드이므로 setValue가 아닌 postValue를 이용합니다.

setValue는 Main Thread, postValue는 Background Thread라고 보면 됩니다.

출처: https://developer.android.com/kotlin/coroutines?hl=ko

참고로, 위에서 withContext(IO)로 한 이유는, 현재 서버가 없기 때문에 fakeItemList를 작성하여 Repository에서 추출해오는 형태이지만, 실제 서비스되는 앱에서는 네트워크 통신을 이용(Retrofit)하여 데이터를 추출해오며, 네트워크 작업은 Dispatchers.IO 디스패처를 이용해야 하기 때문입니다.

 

5. Glide, FlexBox Dependency 추가

build.gradle(Module: app)에서 아래와 같이 dependency를 추가합니다.

//Glide (https://github.com/bumptech/glide)
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

 

//FlexBox (https://github.com/google/flexbox-layout)
implementation 'com.google.android:flexbox:2.0.1'

 

Glide: 이미지 로딩을 위해 사용합니다.

FlexBox: 위에 "tags"를 표시하기 위해 사용합니다(가변적인 레이아웃).

 

 

 

6. WhatToEatAdapter(RecyclerView Adapter), WhatToEatDiffCallback(DiffUtil), FlexBosListAdapter(Flexbox Recyclerview Adapter) 작성

 

(WhatToEatAdapter class)

먼저 RecyclerView Adapter의 기본 속성인 onCreateViewHolder, onBindViewHolder 그리고 ViewHolder를 작성합니다.

Encapsulation을 위해서, WhatToEatViewHolder 클래스 안에 bind 함수와 from 함수를 작성합니다.

bind 함수는 말 그대로 뷰를 바인딩하는 역할을 하며, from은 뷰를 그릴 layout을 참조하기 위한 메써드입니다.

 

(item_layout_what_to_eat.xml)

 

참고로 ListAdapter과 DiffCallback을 사용하는 방법을 알려드리고자 위와 같이 작성하였습니다.

DiffCallback을 사용하면 아이템이 추가되거나 삭제되거나 하는 것을 모두 DiffUtil이 알아서 처리합니다. 결국 notifyDataSetChanged()를 따로 호출해줄 필요가 없게 되는 것이죠!

 

ListAdapter를 상속받으면

onBindViewHolder 메써드 안에서 "getItem(position)"을 볼 수 있으며 getItem이라는 메써드를 제공합니다. 편리하죠?

그리고 fun setList(list: List<WhatToEat>) 함수를 보면 submitList(list)라고 되어있는 것을 볼 수 있습니다.

이 또한 ListAdapter 클래스에서 제공해주는 메서드라서 편리하게 사용하면 됩니다. submitList는 알아서 NotifyDataSetChanged()를 처리해주기 때문에 저희가 따로 무엇을 건드리거나 할 필요가 없습니다.

 

bind 함수 내부를 보면

Glide를 이용하여 http:// 형태의 imageUrl을 로딩하도록 합니다.

RecyclerView에 FlexBoxLayoutManager를 적용시켜주며, FlexDirection.ROW(가로 방향), JustifyContent.FLEX_START(시작점은 왼쪽부터)로 설정해줍니다. 

그리고 item.tags는 WhatToEat class를 보면 String 변수입니다. String 변수이지만 잘 보면 변수 값에 쉼표가 들어가 있습니다. 즉 이 쉼표를 구분점으로 이용하여 item.tags.split(",")로 스플릿 하여 list 형태로 만들어주어 FlexBoxListAdapter에 넘겨주어 adapter를 만들어줍니다.

FlexBoxListAdapter는 아래에 작성해두었으며 기존 RecyclerView.Adapter를 상속하며 크게 다를 것이 없어 설명을 생략하겠습니다.

 

아래 나머지 작성해야 할 파일들입니다. (다 작성해야 최종 결과 화면에 도달할 수 있습니다.)

 

(WhatToEatDiffCallback 클래스)

(FlexBoxListAdapter 클래스)

(rectangle_all_corner_radius_gray_background.xml)

(item_layout_tags.xml)

 

 


[결과 화면]

위와 같이 RecyclerView를 이용한 여러 아이템 리스트 형태로 보여주기, Glide를 이용하여 웹 이미지를 로딩하였으며, FlexBoxLayoutManager을 이용하여 "피자 >" 형태의 RecyclerView 또한 구현하였습니다.

 

물론! 실제 배달의 민족 App처럼 동영상이 Play 되며, Play 되지 않을 때는 해당 영상의 Thumbnail이 보이게 해야 하는데, 이는 ExoPlayer를 이용하여 추후에 다루어 보도록 하겠습니다.

 


[Youtube] 이해를 돕기 위해 직접 보며 따라 할 수 있는 영상 또한 준비하였습니다.

https://www.youtube.com/watch?v=b6t30ciq-DM&t=1143s


[Github] 코드를 다운로드하여서 실행해보시기 바랍니다.

https://github.com/DJDrama/BaeminPractice/tree/EatWhatFragment-ListAdapter%2CGlide%2CFlexBox

 

DJDrama/BaeminPractice

Contribute to DJDrama/BaeminPractice development by creating an account on GitHub.

github.com

 

저도 따라 만들어보고 있지만, 완전히 똑같이 따라 하려면 매우 많은 시간이 들어갑니다. 일단 저도 실력이 부족하여 공부를 해야 하며, 그림이라던지 아이콘도 없고 실제 데이터가 없다 보니 어떻게 만들어야 할지 가끔 눈 앞이 깜깜합니다.

 

다음 편에서는 "찜한가게" 부분을 만들어보도록 하겠습니다.

ViewPager2와 Fragment를 이용하여 만들어보도록 하겠습니다.

 

그럼 이런 허접한 글 읽어주셔서 감사합니다~!

이 포스트가 좋으면 공감(하트) 부탁드립니다. 

모든 댓글과 질문은 늘 환영합니다!!