[Android] Coroutine [1]๐Ÿค”

ํ‘ธ๋ฅธํ•˜๋Š˜ยท2021๋…„ 12์›” 30์ผ
0
post-thumbnail

๋“ค์–ด๊ฐ€๊ธฐ์ „ ...

๐Ÿ“Œ๋ง‰์—ฐํ•˜๊ฒŒ ์ฝ”๋ฃจํ‹ด์„ ์™œ ์‚ฌ์šฉํ• ๊นŒ?

๋น„๋™๊ธฐ์  ํ”„๋กœ๋ž˜๋ฐ์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ๋™๊ธฐ/๋น„๋™๊ธฐ๋ผ๋Š” ์˜๋ฏธ๋Š” ๋ฌด์—‡์ผ๊นŒ?

  • ๋™๊ธฐ : ํ˜„์žฌ ์ž‘์—…์˜ ์‘๋‹ต์ด ๋๋‚จ๊ณผ ๋™์‹œ์— ๋‹ค์Œ ์ž‘์—…์ด ์š”์ฒญ(โŒWait)
    ( ์š”์ฒญ์— ๋”ฐ๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ˜ํ™˜๋˜๊ธฐ ์ „๊นŒ์ง€ ์•„๋ฌด๊ฒƒ๋„ ๋ชปํ•˜๊ณ  ๋Œ€๊ธฐํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.)
  • ๋น„๋™๊ธฐ : ํ˜„์žฌ ์ž‘์—…์˜ ์‘๋‹ต์ด ๋๋‚˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ๋‹ค์Œ ์ž‘์—…์ด ์š”์ฒญ(โญ•๏ธ wait)
    (์š”์ฒญ์— ๋”ฐ๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ˜ํ™˜๋˜๋Š” ์‹œ๊ฐ„ ๋™์•ˆ ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)
    (๋™๊ธฐ์‹๋ณด๋‹ค ์„ค๊ณ„๊ฐ€ ๋ณต์žกํ•˜๊ณ  ๋…ผ์ฆ์ ์ž…๋‹ˆ๋‹ค)

๐Ÿ“Œ ์™œ ๋น„๋™๊ธฐ์ ์ธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ฑ„ํƒํ–ˆ์„๊นŒ?

๊ฒฐ๊ณผ๊ฐ€ ์ฃผ์–ด์ง€๋Š” ์‹œ๊ฐ„ ๋™์•ˆ ๋‹ค๋ฅธ ์ผ์„ ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•จ

๋‹น์‹ ์ด ๋‚š์‹œ๋ฅผ ํ•œ๋‹ค๊ณ  ์˜ˆ๋ฅผ ๋“ค์–ด๋ณด์ž

๋™๊ธฐ

  • ํ•˜๋ฃจ์ข…์ผ ๋ฌผ๊ณ ๊ธฐ ๋‚š์ผ ๋•Œ๊นŒ์ง€ ํ•˜์—ผ์—†์ด ๊ฐ•์„ ๋ฐ”๋ผ๋ณด๋ฉฐ ์•‰์•„์žˆ๋Š” ์ƒํƒœ๋ž‘

๋น„๋™๊ธฐ

  • ๋ฌผ๊ณ ๊ธฐ๊ฐ€ ๋‚š์ผ ๋•Œ๊นŒ์ง€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๊ณผ ์ด์•ผ๊ธฐ๋„ ํ•˜๊ณ  ๋ฐฅ๋„ ๋จน๊ณ  ์ž ๋„ ์ž˜ ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ

๋‘˜ ์ค‘์— ์–ด๋–ค ๋ฐฉ์‹์„ ์ฑ„ํƒํ•  ๊ฒƒ์ธ๊ฐ€? ๋‹น์—ฐํžˆ ๋น„๋™๊ธฐ์‹ ๋ฐฉ์‹์„ ์ฑ„ํƒํ•  ๊ฒƒ์ด๋‹ค.

  • ์–ธ์ œ์žกํž์ง€ ๋ชจ๋ฅด๋Š” ๋ฌผ๊ณ ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฐ๊ณ ํŒŒ์„œ ์ฃฝ์„์ˆ˜๋„ ์žˆ๊ณ 
  • ์‹œ๊ฐ„์„ ๋‹ค์–‘ํ•˜๊ฒŒ ํ™œ์šฉํ• ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

โœ… Use Coroutine

์ฝ”๋ฃจํ‹ด์€ ํ•จ๊ป˜ ์“ฐ๋Š” ๋ฃจํ‹ด ์ด๋‹ค

์ฝ”๋ฃจํ‹ด์˜ "Co"๋Š” with ๋˜๋Š” together๋ฅผ ๋œปํ•ฉ๋‹ˆ๋‹ค

๐ŸŽ ๊ณผ์—ฐ ์™œ ํ•จ๊ป˜ ์“ฐ๋Š” ๋ฃจํ‹ด ์ผ๊นŒ์š”?

  • ์ผ๋ฐ˜ ์ ์ธ ๋ฃจํ‹ด์€ in -> Out์œผ๋กœ ๋‚˜๊ฐ€๋Š” ํ˜•์‹์ž…๋‹ˆ๋‹ค
  • ํ•˜์ง€๋งŒ ์ฝ”๋ฃจํ‹ด์€ in -> Out๋‚˜๊ฐ€๋Š” ๋„์ค‘์— ์ค‘๋‹จ๊ณผ ์žฌ๊ฐœ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

๐Ÿ“ฃ์š”์•ฝ

  • Main-Safe ํ•ด์•ผํ•œ๋‹ค ( Main Thread)๋ฅผ Block ํ•˜์ง€ ์•Š๋Š”๋‹ค
  • Main-Safe ๋ฐ ์—ฌ๋Ÿฌ Thread๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋™์‹œ์„ฑ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค
  • ๋™์‹œ์„ฑ ์‚ฌ์šฉํ•  ๋•Œ ์ฝœ๋ฐฑ๋ณด๋‹ค Coroutine์„ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์ด ๊ฐ€๋…์„ฑ์— ๋” ์ข‹๋‹ค
  • ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๋ณด๋‹ค Coroutine์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ถˆํ•„์š”ํ•œ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ๊ณผ blocking์„ ์—†์•  ์„ฑ๋Šฅ์ด ๋” ์ข‹๋‹ค.

๐ŸŽ ๋“ค์–ด๊ฐ€๊ธฐ์ „์— ์งˆ๋ฌธ

์šฐ๋ฆฌ๊ฐ€ ๋ง‰ํž˜ ์—†๋Š” ํด๋ฆฐํ•œ ์•ฑ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ์–ผ๋งˆ๋‚˜ ๋นจ๋ผ์•ผ ํ• ๊นŒ์š”?

์ด๊ฒƒ์„ ๋ณด์‹œ๋ฉด ์—ฐ์†์ ์ธ ์ด๋ฏธ์ง€๊ฐ€ ๋งˆ์น˜ ์˜์ƒ์ฒ˜๋Ÿผ ๋ณด์—ฌ์„œ ์ธ์‹์ด ๋ฉ๋‹ˆ๋‹ค.
์ด์ฒ˜๋Ÿผ ์‚ฌ๋žŒ์˜ ๋ˆˆ์€ ์ดˆ๋‹น 60 ํ”„๋ ˆ์ž„์ธ ๋ชจ์…˜๊ณผ ๊ทธ ์ด์ƒ์˜ ๋ชจ์…˜์˜ ํฐ ์ฐจ์ด๋ฅผ ๋Š๋ผ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค

๐Ÿ ์ด๋ ‡๊ฒŒ ๋น ๋ฅด๊ฒŒ ๋ณด์ผ๋ ค๋ฉด

1000ms/ 60 frames = 16.666 ms/ frame

์ฐจ์ด๋ฅผ ๋Š๋ผ์ง€ ๋ชปํ•˜๊ฒŒ ํ• ๋ ค๋ฉด 16ms ๋งˆ๋‹ค ์ž‘์—…์„(์ž…๋ ฅ,์ฒ˜๋ฆฌ,ํ†ต์‹ ,๋žœ๋”๋ง) ์ฒ˜๋ฆฌํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค

  • ํ•˜์ง€๋งŒ ,์•ฑ์— ํ•„์š”ํ•œ ์ž‘์—… ์ค‘์—์„œ 16ms ๋ณด๋‹ค ํฐ ๋„คํŠธ์›Œํฌ ํ†ต์‹  / DB์ž‘์—… /JSON ํŒŒ์‹ฑ ๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค
  • ๊ธด ์ž‘์—…์„ ๋ฉ”์ธ์Šค๋ ˆ๋“œ์—์„œ ๋ชจ๋‘ ์ง„ํ–‰ํ•˜๋‹ค๋ณด๋ฉด ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์˜ ๋ณธ๋ž˜ ์—ญํ• ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๊ณ  ํ™”๋ฉด์˜ ๋ฒ„๋ฒ…ํž˜ ํ˜„์ƒ / ANR์„ ๋ฐœ์ƒ์‹œ์ผœ์„œ ์•ฑ์ด ํŠ•๊ธธ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ์€ ์ดˆ๋‹น 60 ํ”„๋ ˆ์ž„์˜ ์—…๋ฐ์ดํŠธ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฌด๊ฐ€ ์ฃผ์–ด์ง€๊ณ  , ์ด๋ฅผ ์ง€ํ‚ค๊ธฐ ์œ„ํ•ด์„œ Main-Thread ๊ฐ€ Blocking ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ๋งค์šฐ ์ค‘์š”ํ•œ ์ผ์ด ๋ฉ๋‹ˆ๋‹ค

Main-Thread์—์„œ ๋„คํŠธ์›Œํ‚น์„ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋ฉด NetworkOnMainThreadException ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ค‘๋‹จํ•˜๋Š” ๋“ฑ ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŽ Main Safe ํ•˜๊ธฐ ์œ„ํ•ด์„œ

Main ํ•จ์ˆ˜์—์„œ Main-Thread๊ฐ€ ์ปดํฌ๋„ŒํŠธ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์†Œ๋“œ์™€ ๊ทธ ์•ˆ์˜ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ ,UI ์ž‘์—…์„ ์‹คํ–‰ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค .
๊ทธ์ค‘ UI ์ž‘์—…์€ Main-Thread์—์„œ๋งŒ ์‹คํ–‰์ด ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ํŠน์ง•(Single-Thread)์ด ์žˆ์Šต๋‹ˆ๋‹ค.

Single-Thread

ํŠน์ • ์ž‘์—…์ด ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ์—์„œ๋งŒ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ์ œํ•œํ•˜๋Š”๊ฒƒ

Single-Thread์˜ ์žฅ์ 

  • ์ž์› ์ ‘๊ทผ์— ๋Œ€ํ•œ ๋™๊ธฐํ™” ์‹ ๊ฒฝ x
  • ๊ฒฝ์Ÿ ์ƒํƒœ / ๊ต์ฐฉ ์ƒํƒœ ์˜ˆ๋ฐฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ž‘์—… ์ „ํ™˜ (Context Switching) ๋น„์šฉ์„ ์š”๊ตฌํ•˜์ง€ ์•Š์•„์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‘๋‹ต์„ฑ์˜ ์œ ์ง€์— ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ UI ์ž‘์—…์€ ๋ฉ”์ธ์Šค๋ ˆ๋“œ์—์„œ๋งŒ ์ด๋ค„์งˆ ์ˆ˜ ์žˆ๊ธฐ๋•Œ๋ฌธ์—, ๋ฉ”์ธ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฐฉํ•ด๋˜๋ฉด ์›ํ™œํ•œ UI ์ž‘์—…์ด ์–ด๋ ค์›Œ์ง€๊ฒŒ ๋œ๋‹ค๋Š” ์ ์„ ์ดํ•ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

๐ŸŽ Android Concurrency

Concurrency์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Main Threead ๋ง๊ณ  ๋ณ„๋„์˜ Thread๋ฅผ ๋‘์–ด์„œ ํ•ญ์ƒ์„ฑ์„ ์œ ์ง€ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

ํ•˜๋‚˜์˜ Process์•ˆ์—๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ Thread๊ฐ€ ์žˆ๊ณ  Thread๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค

๊ทธ๋ฆผ์— Main Thread JVM ํ”„๋กœ์„ธ์Šค๋Š”

  • Main Thread๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด ๊ฐ•์ œ๋กœ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค, JVM์— ์†ํ•œ Thread๋„ ์ข…๋ฃŒ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ Main Thread๋ง๊ณ  ๋‹ค๋ฅธ 2๊ฐœ์˜ Thread๋Š” Main Thread ์ฒ˜๋Ÿผ ์ˆ˜ํ–‰ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด Thread๋Š” ์ข…๋ฃŒ๋˜์–ด๋„ ๋‹ค๋ฅธ Thread์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค .

๊ทธ๋ฆฌํ•˜์—ฌ ๊ตฌ๊ธ€์—์„œ๋Š” Concurrency ์„ ์œ ์ง€ํ•˜๊ธฐ์œ„ํ•œ Dream Code์— ๋Œ€ํ•œ ์—ฐ๊ตฌ๋ฅผ ํ•ด์™”์Šต๋‹ˆ๋‹ค

๐ŸŽ Callback < Coroutine(๊ฐ€๋…์„ฑ up)

Google ์ด ๊ฐ€๋…์„ฑ์ด ์ข‹์€ ์ฝ”๋“œ(Dream Code)๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ํ–ˆ๋˜ ๊ณผ์ •

๐Ÿ Dream Code

  • ์„œ๋ฒ„์ธ fectchUserData() ํ˜ธ์ถœ๋’ค ๊ทธ ๋‚ด์šฉ์„ texview.text์— ๋Œ€์ž…ํ•˜๋Š” ์‚ฌ์ง„์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ NetworkCall ์•ˆ์—์„œ MainThread ์—์„œ Network ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Exceptio์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์™œ Exception์ด ๋ฐœ์ƒํ–ˆ์„๊นŒ? ๋ฐ”๋กœ Main-Safe ๊ทœ์น™์„ ์ง€ํ‚ค์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๐Ÿ Dream Code2

  • UI๋ฅผ UI ์“ฐ๋ ˆ๋“œ์—์„œ ์—…๋ฐ์ดํŠธํ•ด์•ผํ•˜๋Š”๋ฐ ๋ณ„๋„ Thread์—์„œ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

CalledFromWrongThreadException

  • ๋ฉ”์ธ์Šค๋ ˆ๋“œ์—์„œ UI ๋ณ€๊ฒฝํ•ด!!! ๋ฉ”์ธ์Šค๋ ˆ๋“œ์—์„œ ๋งŒ๋“ค์—ˆ์œผ๋‹ˆ!!! ๋œป์ž…๋‹ˆ๋‹ค.

์ฆ‰ , thread์„ UI Thread์ธ Main Thread ์‹คํ–‰๋˜๊ฒŒ ๋ณ€๊ฒฝ์‹œ์ผœ์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ Dream Code3

๊ทธ๋ž˜์„œ ์„œ๋ฒ ์—์„œ ๋ฐ์ดํ„ฐ๋กค ๊ฐ€์ ธ์˜ค๋Š” Thread์—์„œ ๋‹ค์‹œ Main-Thread๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์ฝœ๋ฐฑ์„ ์ค˜์„œ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ํ˜•์‹์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ค‘์ฒฉ์ด ๋˜๋ฉด ์ฝœ๋ฐฑ ์ง€์˜ฅ์ด ๋ฉ๋‹ˆ๋‹ค.

์ผ์ผ์ด Cancel() ํ•ด์„œ Clearํ•˜๋Š” ๊ทธ๋ฆผ

์›ํ•˜๋Š” ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€๋งŒ, ์ฝœ๋ฐฑ์ด ์ฝœ๋ฐฑ์„ ๋ถ€๋ฅด๋Š”, ์ฝœ๋ฐฑ ์ง€์˜ฅ์˜ ์œ„ํ—˜์ด ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Ui ๊ทธ๋ฆด๋•Œ user ๊ฐ์ฒด๊ฐ€ ์ˆ˜์—†์ด ๊ณ„์† ๋ฐ”๋€Œ๊ฑฐ๋‚˜ ์‚ญ์ œ, ์žฌ์ƒ์„ฑ ํ•˜๊ฑฐ๋‚˜ ํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์— ์œ„ํ—˜์ด ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

๐ŸŽ Dream Code์˜ ์™„์„ฑ ๋ฐ ๊ณผ์ •

Coroutines Simplify async code by replacing callbacks

๐Ÿstep[1]

๋‹ค์Œ์„ ๋ณด๋ฉด

  • fecthUser() ํ•จ์ˆ˜๊ฐ€Main-Thread์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ž‘์—…์„ ํ•˜๋ฉด UI์ธ Main-Thread๊ฐ€ Blocking ๋˜๋ฉด์„œ ๊ทธ๋ฆด ์ˆ˜๊ฐ€ ์—†์–ด์ง€๊ธฐ์— ์•ฑ์€ ANR์ด ์ผ์–ด๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ step[2]


๋‹ค์Œ์„ ๋ณด๋ฉด

  • ๊ทธ๋ฆผ์—์„œ api.fetchUser์ธ ๋ณ„๋„์˜ ์“ฐ๋ ˆ๋“œ(Network Thread)๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋‹ค์‹œ Main-Thread๋กœ ๋ฐ”๊ฟ”์„œ ๋ณด๋‚ด์ฃผ๋Š” ๋ฐฉ์‹์„ Switch ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๊ณตํ•˜์ง€๋งŒ ์•„์ง Dream Code์—๋Š” ๊ฐ€๊น์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๐Ÿ step[3]

๋น„๋™๊ธฐ๋ฅผ ์ˆœ์ฐจ์  ์ฝ”๋“œ๋กœ ๋งŒ๋“ค๋‹ค

  • ์ฝ”๋ฃจํ‹ด์˜ suspend ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ์„œ๋ฒ„๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ฝ”๋“œ(fechUser) ์™€ UI๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์ฝ”๋“œ(show(user))๊ฐ€ ์ˆœ์ฐจ์ ์œผ๋กœ ์ž‘์„ฑ๋œ๋‹ค
  • ์ฝœ๋ฐฑ๋„ ์—†๊ณ  ๋ณ„๋„์˜ Thread๋„ ์—†์—ˆ์ง€๋งŒ ์‹ค์ œ ์‹คํ–‰์€ callbackํ˜•ํƒœ๋กœ ์ง„ํ–‰์ด ๋ฉ๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€