Task - YunByungKwan/Fundamental GitHub Wiki

Task

  • ๊ณผ์ œ API ๋ ˆ๋ฒจ ๋ฒ”์œ„: 21 ~ 29
  • MIN SDK: 21
  • Target SDK: 29
  • [ ๋ฒ„์ „๋ช… / ๋ฒ„์ „ / API๋ ˆ๋ฒจ ]
    • ๋กค๋ฆฌํŒ(๋ฒ„์ „ 5) 21 ~ 22
    • ๋งˆ์‹œ๋ฉœ๋กœ(๋ฒ„์ „ 6) 23
    • ๋ˆ„๊ฐ€(๋ฒ„์ „ 7) 24 ~ 25
    • ์˜ค๋ ˆ์˜ค(๋ฒ„์ „ 8) 26 ~ 27
    • ํŒŒ์ด(๋ฒ„์ „ 9) 28
    • ํ€ธ ์ผ€์ดํฌ(๋ฒ„์ „ 10) 29
    • ๋ ˆ๋“œ๋ฒจ๋ฒณ ์ผ€์ดํฌ(๋ฒ„์ „ 11) 30

ํ”„๋กœ์ ํŠธ๋ฅผ ์–ด๋–ป๊ฒŒ ์„ค๊ณ„ํ–ˆ๋Š”์ง€ ์„ค๋ช…ํ•ด ์ฃผ์„ธ์š”.

๋จผ์ € ํฌ๊ฒŒ data, di, ui, util๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค.
ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ๊ณต์‹ ์•ฑ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์ฐธ๊ณ ํ–ˆ๊ณ 
jetpack์— ์žˆ๋Š” ViewModel๊ณผ LiveData, Databinding์„ ์‚ฌ์šฉํ•ด์„œ ์„ค๊ณ„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ data๋ฅผ ๋ณด์‹œ๋ฉด
entityํด๋”์—๋Š” ํ”„๋กœ์ ํŠธ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค๋“ค์ด ์žˆ๊ณ 
remoteํด๋”์—๋Š” Retrofit๊ด€๋ จ service ์ธํ„ฐํŽ˜์ด์Šค ํŒŒ์ผ๊ณผ remoteDataSource๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
repositoryํด๋”์—๋Š” repository๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์˜์กด์„ฑ ์ฃผ์ž…์„ ์œ„ํ•ด์„œ dagger๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•œ ์ด์œ ๋Š” ์œ ๋‹› ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด์„œ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ diํด๋”์—๋Š” dagger์— ํ•„์š”ํ•œ ํŒŒ์ผ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

uiํด๋”์—๋Š” Activity์™€ ViewModel์ด ์žˆ๊ณ ,
MainActivity Recyclerview์— ์‚ฌ์šฉ๋˜๋Š” ListAdapterํŒŒ์ผ๊ณผ BindingAdapterํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ถ”๊ฐ€์ ์œผ๋กœ MainActivity์™€ ๊ด€๋ จ๋œ dagger component์™€ moduleํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

utilํด๋”์—๋Š” dagger ์ ์šฉ์„ ์œ„ํ•ด์„œ applicationํด๋ž˜์Šค๊ฐ€ ์žˆ๊ณ 
์นดํ…Œ๊ณ ๋ฆฌ์˜ ์ฝ”๋“œ๋ฅผ ์ €์žฅํ•˜๋Š” Categoryํด๋ž˜์Šค ํŒŒ์ผ,
๊ธฐํƒ€ ์ƒ์ˆ˜๋“ค ์ €์žฅํ•˜๋Š” ConstantsํŒŒ์ผ,
๊ทธ๋ฆฌ๊ณ  ๊ถŒํ•œ ๊ถŒ๋ จ๋œ objectํŒŒ์ผ์ด ์žˆ๊ณ 
View๊ด€๋ จ ํ™•์žฅํ•จ์ˆ˜๋“ค์„ ์ •์˜ํ•œ ViewExtํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„๋ถ€ํ„ฐ ์กฐ๊ธˆ ์„ธ๋ถ€์ ์œผ๋กœ ๋ง์”€๋“œ๋ฆฌ์ž๋ฉด

entity๋Š” API๊ด€๋ จ ํด๋ž˜์Šค๋“ค์ด๊ณ  ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•œ ๊ฒŒ Coordinate ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.
Coordinateํด๋ž˜์Šค๋Š” ์นด์นด์˜ค๋งต์˜ ์ง€๋„ ์ค‘์‹ฌ ์ขŒํ‘œ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

remote๋Š” ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์‹œ retrofit์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋น„๋™๊ธฐ ํ†ต์‹ ์— coroutine์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ apiํ•จ์ˆ˜๋ฅผ suspend๋กœ ๋งŒ๋“ค์—ˆ๊ณ  remoteDataSource์—์„œ ์ด apiํ•จ์ˆ˜๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

repository์—์„œ๋Š” remoteDataSource ์˜์กด์„ฑ์„ ์ฃผ์ž… ๋ฐ›์•„์„œ remoteDataSource ๊ด€๋ จ ํ•จ์ˆ˜๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  Room์œผ๋กœ ๋„คํŠธ์›Œํฌ ์บ์‹ฑ ์ถ”๊ฐ€ํ• ๊นŒ ์ž ๊น ๊ณ ๋ฏผํ–ˆ์ง€๋งŒ, ์ธํ„ฐ๋„ท์ด ๋Š๊ฒผ์„ ๊ฒฝ์šฐ ์นด์นด์˜ค ๋งต์ด ์ผ๋‹จ ๋ณด์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—
์บ์‹ฑ์€ ๋ถˆํ•„์š”ํ•  ๊ฑฐ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด์„œ ๋ณ„๋„๋กœ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์ด์ œ ui์ชฝ์œผ๋กœ ๋„˜์–ด๊ฐ€๋ฉด
๋จผ์ € ๊ณผ์ œ๊ฐ€ ์•ฐ๋ทธ๋Ÿฐ์Šค ์šด์ „์‚ฌ๊ฐ€ ๋ณด๋Š” ์•ฑ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ง€๋„๊ฐ€ ์ž‘์œผ๋ฉด ํ™”๋‚  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ๋ฅผ ์ ‘์„ ์ˆ˜ ์žˆ๊ฒŒ ๋ชจ์…˜ ๋ ˆ์ด์•„์›ƒ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ง€๋„ ์•ฑ์ด๋‹ค ๋ณด๋‹ˆ ํ™”๋ฉด์„ ๊ฐ€๋กœ๋กœ ๋Œ๋ ค์„œ
๋งŽ์ด ๋ณผ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ™”๋ฉด ํšŒ์ „ํ•ด๋„ ์›๋ž˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋“ค๊ณ  ์žˆ๊ธฐ ์œ„ํ•ด์„œ ViewModel์—์„œ
ํ™”๋ฉด ์ค‘์‹ฌ ์ขŒํ‘œ, ๊ฒ€์ƒ‰ ์นดํ…Œ๊ณ ๋ฆฌ, ... ๋ฅผ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

MainActivity๋ฅผ ๋ณด๋ฉด ํฌ๊ฒŒ onClickํ•จ์ˆ˜๋“ค, listener, ๋งˆ์ปค ์–ด๋ށํ„ฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

Permission

  • ACCESS_FINE_LOCATION: GPS์™€ ๋„คํŠธ์›Œํฌ๋กœ ์œ„์น˜๋กœ ๋‹จ๋ง๊ธฐ ์œ„์น˜๋ฅผ ์‹๋ณ„
  • ACCESS_COARSE_LOCATION: ๋„คํŠธ์›Œํฌ๋ฅผ ์ด์šฉํ•ด์„œ ๋‹จ๋ง๊ธฐ ์œ„์น˜๋ฅผ ์‹๋ณ„
  • ์•ˆ๋“œ๋กœ์ด๋“œ 10(29)๋ถ€ํ„ฐ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์œ„์น˜ ๊ถŒํ•œ๊ณผ ํฌ๊ทธ๋ผ์šด๋“œ ์œ„์น˜ ๊ถŒํ•œ์ด ๋‚˜๋‰จ
  • ํ•ญ์ƒ ํ—ˆ์šฉ - ๋ฐฑ๊ทธ๋ผ์šด๋“œ, ํฌ๊ทธ๋ผ์šด๋“œ ์œ„์น˜๋ฅผ ๋ชจ๋‘ ํ—ˆ์šฉํ•œ๋‹ค๋Š” ์˜๋ฏธ
  • ์•ฑ ์‚ฌ์šฉ ์ค‘์—๋งŒ ํ—ˆ์šฉ - ํฌ๊ทธ๋ผ์šด๋“œ ์œ„์น˜ ๊ถŒํ•œ๋งŒ ํ—ˆ์šฉํ•œ๋‹ค๋Š” ์˜๋ฏธ
  • Android 11(30)
    • ์•ฑ ์‚ฌ์šฉ ์ค‘์—๋งŒ ํ—ˆ์šฉ
    • ์ด๋ฒˆ๋งŒ ํ—ˆ์šฉ
    • ๊ฑฐ๋ถ€
  • ์œ„์น˜ ๊ถŒํ•œ(ACCESS_FINE_LOCATION)์„ ์™œ ์š”์ฒญํ•ด์•ผ ํ•˜๋Š”์ง€?
    • ์œ„ํ—˜ ๊ถŒํ•œ์ด๊ธฐ ๋•Œ๋ฌธ์—
    • GPS๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ
  • ์œ„์น˜ ์„ค์ •์„ ํ•˜๋Š” ์ด์œ ?
    • ์ง€๋„์— ํ˜„์žฌ ๋‚ด ์œ„์น˜๋ฅผ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด..??
  • ๊ฒฝ์šฐ์˜ ์ˆ˜
    • ์œ„์น˜ ๊ถŒํ•œ X(๊ฑฐ๋ถ€) / ์œ„์น˜ ์„ค์ • X

    • ์œ„์น˜ ๊ถŒํ•œ X(๊ฑฐ๋ถ€) / ์œ„์น˜ ์„ค์ • O

    • ์œ„์น˜ ๊ถŒํ•œ O(์Šน์ธ) / ์œ„์น˜ ์„ค์ • X

    • ์œ„์น˜ ๊ถŒํ•œ O(์Šน์ธ) / ์œ„์น˜ ์„ค์ • O

    • ์œ„์น˜ ์ •๋ณด ์•ก์„ธ์Šค ๊ถŒํ•œ ์œ ํ˜•

    • ํฌ๊ทธ๋ผ์šด๋“œ ์œ„์น˜

    • ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์œ„์น˜ ์ „์ฒด์ ์ธ ๊ตฌ์กฐ๋ฅผ ๋จผ์ € ๋ง์”€๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.
      ์•ฑ์˜ ๊ตฌ์กฐ์˜ ๊ฒฝ์šฐ, ์•ˆ๋“œ๋กœ์ด๋“œ ๊ถŒ์žฅ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ๊ตฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.
      ๊ทธ๋ž˜์„œ RemoteDataSoure -> Repository -> ViewModel -> Activity ๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
      ๊ทธ๋ฆฌ๊ณ  ์˜์กด์„ฑ ์ฃผ์ž…์—๋Š” Dagger๋ฅผ ์‚ฌ์šฉํ–ˆ๊ณ , ๋น„๋™๊ธฐ ํ†ต์‹ ์—๋Š” ์ฝ”๋ฃจํ‹ด์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
      Dagger๋ฅผ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š”

Coroutine์„ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š”

[ MainActivity ] MainActivity์—์„œ ์ฒ˜์Œ์— ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ดˆ๊ธฐํ™”๋ฅผ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  SDK๋ฒ„์ „์ด 23 ์ด์ƒ์ผ ๊ฒฝ์šฐ ACCESS_FINE_LOCATION์— ๋Œ€ํ•œ ํผ๋ฏธ์…˜ ์ฒดํฌ๋ฅผ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ฒ˜์Œ์— ๊ถŒํ•œ์ด ์Šน์ธ๋๋Š”์ง€ ์•ˆ๋๋Š”์ง€๋กœ ๋‚˜๋‰˜๊ณ ์š”. ์Šน์ธ์ด ์ด๋ฏธ ๋œ ๊ฒฝ์šฐ,

[์˜ˆ์ƒ ์งˆ๋ฌธ]

  • ์™œ ACCESS_FINE_LOCATION ๊ถŒํ•œ๋งŒ ์š”์ฒญํ–ˆ๋Š”์ง€?
    • ๊ฐ€์ด๋“œ์— ๋‚˜์˜จ๋Œ€๋กœ ACCESS_FINE_LOCATION ๊ถŒํ•œ์„ ์š”์ฒญํ–ˆ๋‹ค.
  • ACCESS_FINE_LOCATION ๊ถŒํ•œ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ด๋‹ฌ๋ผ

์ฒ˜์Œ ์ง„์ž… ์‹œ

  1. ๊ฒ€์ƒ‰์„ ํ•˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ

  2. ๊ฒ€์ƒ‰์„ ํ•œ ๋ฒˆ ์ด์ƒ ํ•œ ๊ฒฝ์šฐ

[์š”๊ตฌ ์‚ฌํ•ญ]

  • ์นด์นด์˜ค ๋งต ์—ฐ๋™
  • ์นดํ…Œ๊ณ ๋ฆฌ(๋ณ‘์›, ์•ฝ๊ตญ, ์ฃผ์œ ์†Œ)์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ ๊ฒ€์ƒ‰
  • ์ง€๋„ ์ฒ˜์Œ ์œ„์น˜๋Š” ํ˜„์žฌ ์œ„์น˜๋กœ ํ‘œ์‹œ
  • ๋งˆ์ปค ๋ˆ„๋ฅผ ๊ฒฝ์šฐ ๋งˆ์ปค ์œ„์น˜๋กœ ์ง€๋„ ์ค‘์‹ฌ์ด ์ด๋™
  • ๊ฒ€์ƒ‰์„ ํ•˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ->

suspendCancellableCoroutine

  • suspendCoroutine์ฒ˜๋Ÿผ coroutine์„ ์ผ์‹œ์ •์ง€ํ•œ๋‹ค
  • ๊ทธ๋Ÿฌ๋‚˜ CancellableContunuation์„ ์ œ๊ณตํ•˜๋ฉด์„œ
  • ์ผ์‹œ์ •์ง€๋œ ๋™์•ˆ์— coroutine job์ด ์ทจ์†Œ๋˜๊ฑฐ๋‚˜ ์™„๋ฃŒ๋ ๋•Œ CancellationException์„ ๋˜์ง„๋‹ค?

CancellableContinuation

  • invokeOnCancellation(handler: CompletionHandler): ์ด continuation์˜ ์ทจ์†Œ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ํ˜ธ์ถœํ•  ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋กํ•œ๋‹ค

Continuation vs CancellableContinuation

  • Continuation: Tํƒ€์ž…์˜ value๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ค‘๋‹จ์  ํ›„์˜ continuation(interface)
    • [ ๋‚ด๋ถ€์— ๊ฐ–๊ณ  ์žˆ๋Š” ํ•จ์ˆ˜๋“ค ]
    • CoroutineContext ๋ณ€์ˆ˜
    • resumeWith(result: Result): ๋งˆ์ง€๋ง‰ ์ค‘๋‹จ์ ์˜ ๋ฆฌํ„ด๊ฐ’์œผ๋กœ์„œ ์„ฑ๊ณต ๋˜๋Š” ์‹คํŒจ ๊ฒฐ๊ณผ๋ฅผ ๋„˜๊ฒจ์ฃผ๋ฉด์„œ ์ฝ”๋ฃจํ‹ด ์‹คํ–‰์„ ์žฌ๊ฐœํ•จ
    • [ ํ™•์žฅ ํ•จ์ˆ˜๋“ค ]
    • resume(value: T) = resumeWith(Result.success(value))
    • resumeWithException(exception: Throwable) = resumeWith(Result.failure(exception))
  • CancellableContinuation
    • [ ์ƒํƒœ ๋ณ€์ˆ˜๋“ค ]
    • isActive
    • isCompleted
    • isCancelled
    • [ ํ•จ์ˆ˜๋“ค ]
    • public fun tryResume(value: T, idempotent: Any? = null): Any?
    • public fun tryResume(value: T, idempotent: Any?, onCancellation: ((cause: Throwable) -> Unit)?): Any?
    • public fun tryResumeWithException(exception: Throwable): Any?
    • public fun completeResume(token: Any)
    • public fun initCancellability()
    • public fun cancel(cause: Throwable? = null): Boolean : continuation์„ ์ทจ์†Œํ•จ. ์ทจ์†Œ๋˜๋ฉด true๋ฅผ ๋ฐ˜ํ™˜
    • public fun invokeOnCancellation(handler: CompletionHandler) : ์ด continuation์„ ์ทจ์†Œํ• ๋•Œ ๋™์‹œ์— ํ˜ธ์ถœํ•  ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋ก
    • public fun CoroutineDispatcher.resumeUndispatched(value: T)
    • public fun CoroutineDispatcher.resumeUndispatchedWithException(exception: Throwable)
    • public fun resume(value: T, onCancellation: ((cause: Throwable) -> Unit)?)

Retrofit์˜ suspend ํ•จ์ˆ˜

Retrofit์— suspend ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ euqueue๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ 

  • onResponse์—์„œ continuation.resume()์„ ํ˜ธ์ถœํ•จ
  • ๊ทธ ์™ธ์— ์‹คํŒจํ•  ๊ฒฝ์šฐ continuation.resumeWithException()์„ ํ˜ธ์ถœํ•จ

viewModelScope

  • supervisorJob:

RecyclerView ๊ด€๋ จ

  • ListAdapter๋ง๊ณ  ๊ทธ๋ƒฅ recyclerview adapter ๊ตฌํ˜„์‹œ, ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝํ•  ๋•Œ notifyDataSetChanged()๋ฅผ ๋ถ€๋ฅด๋ฉด ๋ฆฌ์ŠคํŠธ๋ฅผ ์ „์ฒด ๋‹ค ๋ฐ”๊ฟ”์•ผ ํ•˜๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค
  • notifyDataSetChanged()๋Š” ๋ฆฌ์ŠคํŠธ๊ฐ€ ๊นœ๋นก์ด๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.
  • ๊ทธ๋ž˜์„œ android์—์„œ ๋งŒ๋“  diffUtil์€ ํ˜„์žฌ ๋ฐ์ดํ„ฐ ๋ฆฌ์ŠคํŠธ์™€ ๊ต์ฒด๋  ๋ฆฌ์ŠคํŠธ๋ฅผ ๋น„๊ตํ•ด์„œ ์ง„์งœ ๋ฐ”๋€Œ์–ด์•ผ ํ•  ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ”๊ฟ”์ค€๋‹ค.
  • ๊ทผ๋ฐ ๋ฉ”์ธ์Šค๋ ˆ๋“œ์—์„œ ์ด๊ฑธ ๋น„๊ตํ•˜๋ฉด ๋ธ”๋ฝ์„ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํ•˜๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค..=> ๊ทธ๋ž˜์„œ AsyncListDiffer๊ฐ™์ด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์ง€์›ํ•ด์ฃผ๋Š” ํ™•์žฅ ํด๋ž˜์Šค๋„ ๋‚˜์˜ด
  • ๊ทธ๋Ÿฌ๋‚˜ ListAdapter๊ฐ€ ํ›จ์”ฌ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๋‹ค(๋‚ด๋ถ€์ ์œผ๋กœ AsyncListDiffer๋ฅผ ์‚ฌ์šฉํ•จ)
  • AsyncListDiffer๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ๋กœ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋น„๊ตํ•œ๋‹ค. => newFixedThreadPool(2)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • diffUtil์€ ๋‚ด๋ถ€์ ์œผ๋กœ diff ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•œ๋‹ค.
    • ์‹œ๊ฐ„๋ณต์žก๋„: O(N + D^2 + N'^2)
    • ๊ณต๊ฐ„๋ณต์žก๋„: O(N) (N๊ฐœ์˜ ์•„์ดํ…œ์ด ์žˆ๋Š” ๊ฒฝ์šฐ)
    • ๊ณต๊ฐ„์—๋Š” ์ตœ์ ํ™”๋˜์–ด ์žˆ์ง€๋งŒ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๊ฝค ๋†’์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜(๊ทธ๋ž˜์„œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ์—์„œ ๋Œ๋ ค์•ผ ํ•œ๋‹ค)

์ฝ”๋“œ ์ˆ˜์ •์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„...

  • PlaceListAdapter -> diffUtilCallback ๋ถ€๋ถ„

    companion object {
        val diffUtilCallback = object: DiffUtil.ItemCallback<Place>() {
            // oldItem == newItem ==> oldItem.id == newItem.id ๋กœ ๋ฐ”๊ฟ”์•ผ ํ• ๋“ฏ..
            override fun areItemsTheSame(oldItem: Place, newItem: Place): Boolean = oldItem == newItem
    
            // ์–˜๋Š” ๋งž์Œ ์™œ๋ƒ๋ฉด equals ์˜ค๋ฒ„๋ผ์ด๋“œํ•ด์„œ ํ•„๋“œ๊ฐ’๋“ค ๋น„๊ตํ•˜๋„๋ก ํ•˜๊ณ  equalsํ•จ์ˆ˜๋ฅผ ์“ฐ๋ฉด ๋˜๋Š”๋ฐ ์ง€๊ธˆ equals๋ฅผ ์“ฐ๊ณ  ์žˆ๊ณ ,
            // data class์ด๋‹ค ๋ณด๋‹ˆ ์•Œ์•„์„œ equals๊ฐ€ ๋‚ด๋ถ€ ํ•„๋“œ๋“ค ๋น„๊ตํ•˜๋„๋ก ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ
            override fun areContentsTheSame(oldItem: Place, newItem: Place): Boolean
                  = oldItem == newItem
        }
    }
  • ListAdapter์— ์•„์ดํ…œ ํด๋ฆญ ์ด๋ฒคํŠธ ๋„ฃ์„ ๊ฒฝ์šฐ?
    ViewHolder ํด๋ž˜์Šค์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋  ๋“ฏ

    init {
        itemView.setOnClickListener {
            val pos = adapterPosition
            if(pos != RecyclerView.NO_POSITION) {
                binding.place?.let {
                    val intent = Intent(Intent.ACTION_VIEW, Uri.parse(it.placeUrl))
                    ContextCompat.startActivity(itemView.context, intent, null)
                }
            }
        }
    }
โš ๏ธ **GitHub.com Fallback** โš ๏ธ