๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿค2024 ์•ˆ๋“œ๋กœ์ด๋“œ/๊ธฐ์ˆ™์‚ฌ ํ”„๋กœ์ ํŠธ ๊ธฐ๋ก

android Flow ์•Œ์•„๋ณด๊ธฐ

by hyeonha 2024. 1. 21.

๋ชฉ์ฐจ

    Flow ์ดํ•ดํ•˜๊ธฐ

    ์ŠคํŠธ๋ฆผ์€ ์ž…๋ ฅ์žฅ์น˜๋‚˜ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋“ค์–ด์˜ค๋Š” ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์ฝ์–ด๋“ค์ด๋ฉด์„œ ์ถœ๋ ฅ ์žฅ์น˜๋‚˜ ๋™์˜์ƒ ํ”Œ๋ ˆ์ด์–ด๋กœ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ๋‚ด๋ณด๋‚ด๋Š” ์—ญํ• ์„ ํ•˜๋Š” ๊ฐ์ฒด์ด๋‹ค.

     

    ์ฝ”ํ‹€๋ฆฐ์˜ ํ”Œ๋กœ์šฐ๋Š” ๋‹จ์ผ ๊ฐ’๋งŒ ๋ฐ˜ํ™˜ํ•˜๋Š” suspend ํ•จ์ˆ˜์™€ ๋‹ฌ๋ฆฌ ์—ฌ๋Ÿฌ ๊ฐ’์„  ์ˆœ์ฐจ์ ์œผ๋กœ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” ์œ ํ˜•์ด๋‹ค.

    ์˜ˆ๋ฅผ ๋“ค์–ด Flow๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์—์„œ ์‹ค์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    Flow๋Š” ์ฝ”๋ฃจํ‹ด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋นŒ๋“œ๋˜์–ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ์˜ ๊ฐœ๋…์ด๋‹ค.  ์ด ๋•Œ ๋‚ด๋ณด๋‚ด๋Š” ๊ฐ’์„ ๋™์ผํ•œ ์œ ํ˜•์ด์–ด์•ผํ•œ๋‹ค. Flow<Int> ์˜ ๊ฒฝ์šฐ ์ •์ˆ˜ ๊ฐ’์„ ๋‚ด๋ณด๋‚ด๋Š” ํ๋ฆ„์„ ๋งํ•œ๋‹ค.

     

    [kotlin flows in practice ๋‚ด์šฉ ์ •๋ฆฌ] 

     

     

     

    ์ด ๋•Œ์—๋Š” ๊ทธ๋ž˜์„œ ํ˜ธ์ˆ˜๊นŒ์ง€ ๊ฐ€๋Š” ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ณ  ๋‹ค๋ฅธ ๊ณณ์—์„œ ๋ฌผ์„ ์ฐพ์•„์•ผํ•œ๋‹ค.

    ์ด๋Ÿฌํ•œ ์‹คํŒจ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ๊ฒช์€ ํ›„ ์ผ์ข…์˜ ์ธํ”„๋ผ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒŒ ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.

     

     

     

    ๊ทธ๋ž˜์„œ ๋‹ค์Œ์— ํ˜ธ์ˆ˜๋กœ ๊ฑธ์–ด๊ฐˆ ๋•Œ ํŒŒ์ดํ”„๋ฅผ ์„ค์น˜ํ–ˆ๋‹ค.

    ์ด์ œ ๋ฌผ์ด ํ•„์š”ํ•  ๋•Œ ํ˜ธ์ˆ˜๊ฐ€ ๋งˆ๋ฅด์ง€ ์•Š์•˜๋‹ค๋ฉด ๊ผญ์ง€๋ฅผ ์—ด๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฌผ์ด ๋‚˜์˜จ๋‹ค.

     

     

    ์ด๋ ‡๊ฒŒ ํŒŒ์ดํ”„๋ฅผ ์„ค์น˜ํ•˜๋ฉด ,์—ฌ๋Ÿฌ ์†Œ์Šค์˜ ๋ฐ์ดํ„ฐ์ธ ์ฆ‰ ๋ฌผ์ค„๊ธฐ๋ฅผ ํ•ฉ์น  ์ˆ˜ ์žˆ๋‹ค.

    ์ด์ œ ํŒ์ตธ๋Š” ํ˜ธ์ˆ˜๊ฐ€ ๋ง๋ž๋Š”์ง€ ํ™•์ธํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

     

     

     

     

     

    ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ์—์„œ๋Š” ๊ฐ„๋‹จํ•œ ๊ฒฝ๋กœ๋ฅผ ํ†ตํ•ด ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋‹ค.

    ์˜ˆ๋ฅผ ๋“ค์–ด ๋ทฐ๊ฐ€ ์‹œ์ž‘๋˜๋ฉด ViewModel์— ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๊ณ  ViewModel์ด data layer์— ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•œ๋‹ค. suspend ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด ๊ณผ์ •์„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

    ํ•˜์ง€๋งŒ ํ•œ๋™์•ˆ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ํŒ์ตธ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ธํ”„๋ผ์— ํˆฌ์žํ•˜๋Š” ๊ฒŒ ๋‚ซ๋‹ค๋Š” ๊ฑธ ๊นจ๋‹ซ๊ฒŒ ๋œ๋‹ค.

     

     

     

    ๊ด€์„ ์„ค์น˜ํ•˜๊ณ ๋‚˜๋ฉด ๋ฐ์ดํ„ฐ ์†Œ์Šค ์—…๋ฐ์ดํŠธ๊ฐ€ ์ž๋™์œผ๋กœ ๋ทฐ์—๊นŒ์ง€ ์ „๋‹ฌ๋œ๋‹ค. ๋”์ด์ƒ ํ˜ธ์ˆ˜๋กœ ๊ฑธ์–ด๊ฐˆ ํ•„์š”๊ฐ€ ์—†๋‹ค.

     

    ์ด๋Ÿฐ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์Šคํ…œ์„ Reactive : ๋ฐ˜์‘ํ˜•์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ๊ด€์ฐฐํ•˜๋Š” ์ชฝ์ด ๊ด€์ฐฐ ๋Œ€์ƒ์˜ ๋ณ€ํ™”์— ์ž๋™์œผ๋กœ ๋ฐ˜์‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    ๊ทธ๋ฆฌ๊ณ  ๋ฐ์ดํ„ฐ๋Š” ํ•œ ๋ฐฉํ–ฅ์œผ๋กœ ํ๋ฅด๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ๋„ ์ค„์–ด๋“ค๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

     

    ๊ทธ๋Ÿผ ๋ฐ์ดํ„ฐ ๋ฒ  ์ด์Šค๋Š” ์›๊ฒฉ ๋ฐ์ดํ„ฐ ์†Œ์Šค์—  ๊ฐ ํ•ญ๋ชฉ์„ ๋กœ๋“œํ•˜๋ผ๊ณ  ์ง€์‹œํ•œ๋‹ค.

     

    ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋™์•ˆ ๋ทฐ์—์„œ ๋กœ๋”ฉ ์ค‘์ธ ์Šคํ”ผ๋„ˆ๋ฅผ ํ‘œ์‹œํ•˜๊ฒŒ ๋œ๋‹ค.

    ์ฆ‰, ์•ˆ๋˜๋Š” ๊ฑด ์•„๋‹ˆ์ง€๋งŒ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์šด ๋ฐฉ๋ฒ•์ด๋‹ค.

     

    ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฐฉํ–ฅ์œผ๋กœ ํ๋ฅด๊ฒŒ ํ•˜๊ณ  ์ˆ˜๋„๊ด€ ์—ญํ• ์„ ํ•˜๋Š” ์ธํ”„๋ผ๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ์„ ๊ฒฐํ•ฉํ•˜๊ณ  ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

     

    ๋ฌด์–ธ๊ฐ€ ๋ฐ”๋€Œ์–ด์„œ ์ˆ˜์ •์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์•„์›ƒํ•˜๋ฉด ๊ด€์„ ๋‹ค์‹œ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

    ์ด๋Ÿฐ ๊ฒฐํ•ฉ๊ณผ ๋ณ€ํ™˜์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด ๋„๊ตฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค ! 

    ์ด๋ฅผ ์œ„ํ•ด์„œ ์˜ค๋Š˜ ์„ธ์…˜์—์„œ๋Š”  Kotlin Flow๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.

     


     

    Kotlin Flow<T> 

    Flow๋Š” ๋ฌผ์ด ์•„๋‹ˆ๋ฏ€๋กœ ์–ด๋–ค ์œ ํ˜•์ด๋“  ๊ฐ€๋Šฅํ•˜๋‹ค.

    ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋‚˜ UI ์ƒํƒœ๋„ ๋  ์ˆ˜ ์žˆ๋‹ค. 

     

    ์šฉ์–ด ์ •์˜

     

    ์ƒ์‚ฐ์ž๋Š” ๋ฐ์ดํ„ฐ๋ฅผ Flow์— ์ž…๋ ฅํ•˜๊ณ  ์†Œ๋น„์ž๋Š” Flow์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•œ๋‹ค.

     

     

    android์—์„œ๋Š” ๋ฐ์ดํ„ฐ ์†Œ์Šค๋‚˜ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๊ฐ€ ์ „ํ˜•์ ์ธ ์•ฑ ๋ฐ์ดํ„ฐ ์ƒ์‚ฐ์ž์ด๋‹ค.

    ์ตœ์ข…์ ์œผ๋กœ ํ™”๋ฉด์— ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ui๊ฐ€ ์†Œ๋น„์ž ์—ญํ• ์„ ํ•œ๋‹ค.

     

    Creating Flows : Flow๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•

    ๋จผ์ € ํ˜ธ์ˆ˜๋กœ ๊ฑธ์–ด๊ฐ€์•ผํ•œ๋‹ค .๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ํ”Œ๋กœ ์ง์ ‘ ๋งŒ๋“ค ํ•„์š”์—†๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ์ฝ”๋ฃจํ‹ด์— Flow๊ฐ€ ์ด๋ฏธ ๊ฒฐํ•ฉ๋˜์–ด ์žˆ๋‹ค.

     

    ๊ฐœ๋ฐœ์ž๋Š” ๋ฐ์ดํ„ฐ ์ƒ์„ฑ๋ฐฉ๋ฒ•์„ ๋ชฐ๋ผ๋„ ํŒŒ์ดํ”„์— ์—ฐ๊ฒฐํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

     

     

    Room์„ ์˜ˆ๋กœ ๋“ค์–ด๋ณด์ž

    List<Codelab> ํƒ€์ž…์˜  Flow๋ฅผ ๋…ธ์ถœํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์•Œ๋ฆฐ๋‹ค. Room ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ƒ์‚ฐ์ž ์—ญํ• ์„ ๋งก์•„์„œ 

    ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์„ ๋•Œ๋งˆ๋‹ค ์ฟผ๋ฆฌ ๋‚ด์šฉ์„ ์ „์†กํ•œ๋‹ค.

     

    ํ”Œ๋กœ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด์•ผํ•  ๋•Œ ์˜ต์…˜

    - ํ”Œ๋กœ ๋นŒ๋”

    userMessageDatatSource์—์„œ ์ˆ˜์‹œ๋กœ ์•ฑ์—์„œ ์˜จ ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•˜๋ ค๊ณ  ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž.

     

    ๋ฉ”์‹œ์ง€ ๋ชฉ๋ก ์œ ํ˜•์˜ ํ”Œ๋กœ๋กœ ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€๋ฅผ ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋•Œ flow๋ฅผ ๋งŒ๋“œ๋ ค๋ฉด flow ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค. flow๋Š” ์ฝ”๋ฃจ์นœ ์ปจํ…์ŠคํŠธ์—์„œ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— flow ๋นŒ๋”๋Š” suspend ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

     

     

    ๋‚ด๋ถ€์—์„œ while(true) ๋ฃจํ”„๋กœ ๋ฐ˜๋ณตํ•˜๊ฒŒ ํ•˜๊ณ , ๋จผ์ € messageApi๋ฅผ ํ†ตํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

    ๊ฐ€์ ธ์˜จ ๋ฉ”์‹œ์ง€๋ฅผ emit ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋…ธ์ถœ์‹œํ‚จ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ปฌ๋ ‰ํ„ฐ๊ฐ€ ์•„์ดํ…œ์„ ๋ฐ›์„ ๋•Œ๊นŒ์ง€ ์ฝ”๋ฃจํ‹ด์„ ์ค‘๋‹จ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

     

    ๋งˆ์ง€๋ง‰์œผ๋กœ ์ผ์ • ์‹œ๊ฐ„ ์ฝ”๋ฃจํ‹ด์„ ์ค‘๋‹จํ•œ๋‹ค.

    ์œ„ flow๋Š” ๋™์ผํ•œ ์ฝ”๋ฃจํ‹ด์—์„œ ์—ฐ์‚ฐ์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์ง„ํ–‰ํ•˜๋ฉฐ ๊ด€์ฐฐ์ž๊ฐ€ ์‚ฌ๋ผ์ง€๊ณ  ์•„์ดํ…œ ์ˆ˜์ง‘์ด ์ค‘๋‹จ๋˜๋ฉด ๋ฉˆ์ถ”๊ฒŒ ๋œ๋‹ค.

     

    flow ๋นŒ๋”์— ์ „๋‹ฌ๋œ suspend ๋ธ”๋ก์€ ์ƒ์‚ฐ์ž ๋ธ”๋ก์ด๋ผ๊ณ ๋„ ํ•œ๋‹ค.

    Collecting Flows 

    Android์—์„œ ์ƒ์‚ฐ์ž์™€ ์†Œ๋น„์ž ๊ฐ„์˜ ๊ณ„์ธต์€ ๊ทธ ์ดํ›„์— ๊ณ„์ธต ์š”๊ตฌ ์‚ฌํ•ญ์— ๋งž๊ฒŒ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

    ํ”Œ๋กœ๋ฅผ ๋ณ€ํ™˜ํ•˜๋ ค๋ฉด ์ค‘๊ฐ„ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

     

     

    latestMessage ์ŠคํŠธ๋ฆผ์ด ํ”Œ๋กœ์˜ ์‹œ์ž‘์ ์ด๋ผ๊ณ  ํ•˜๋ฉด  map ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•ด  ๋ฐ์ดํ„ฐ ์†Œ์Šค์—์„œ ๋ฐ›์€ ์›๋ณธ ๋ฉ”์‹œ์ง€๋ฅผ  ๋‹ค๋ฅธ ํƒ€์ž…(์—ฌ๊ธฐ์„œ๋Š” MessageUiModel)์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    ๊ฐ ์—ฐ์‚ฐ์ž๋Š” ๊ธฐ๋Šฅ์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ์ƒˆ ํ”Œ๋กœ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

    ์ŠคํŠธ๋ฆผ์„ ํ•„ํ„ฐ๋งํ•˜์—ฌ ์ค‘์š”ํ•œ ์•Œ๋ฆผ์ด ํฌํ•จ๋œ ํ•ด๋‹น ๋ฉ”์‹œ์ง€๋ฅผ flow๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

     

    ๊ทธ๋Ÿฌ๋ฉด ์ŠคํŠธ๋ฆผ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜๋Š” ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ๊นŒ?

     

    catch ์—ฐ์‚ฐ์ž๋Š” ์—…์ŠคํŠธ๋ฆผ flow์—์„œ ํ•ญ๋ชฉ์„ ์ฒ˜๋ฆฌํ•˜๋Š”๋™์•ˆ ๋ฐœ์ƒํ• ๋งŒํ•œ ์—๋Ÿฌ๋ฅผ ์ฐพ๋Š”๋‹ค.

    upstram flow๋Š” ํ”„๋กœ๋“€์„œ ๋ธ”๋ก์—์„œ ์ƒ์„ฑํ•œ flow์ด๊ณ   ํ˜„์žฌ ์—ฐ์‚ฐ์ž ์ „์— ์ด ๋ธ”๋ก์„ ํ˜ธ์ถœํ•œ๋‹ค.

     

    ํ˜„์žฌ ์—ฐ์‚ฐ์ž ์ดํ›„์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์„ downstream flow๋ผ๊ณ  ํ•œ๋‹ค.

    Collecting Flows

    ์ผ๋ฐ˜์ ์œผ๋กœ flow ์ˆ˜์ง‘์€ UI ๊ณ„์ธต์—์„œ ์ผ์–ด๋‚œ๋‹ค. ํ™”๋ฉด์— ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•  ์œ„์น˜์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค

    ์šฐ๋ฆฌ ์˜ˆ์‹œ์—์„œ๋Š” ๋ชฉ๋ก์— ์ตœ์‹  ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ๋ž˜์•ผ ํŒ์ตธ๊ฐ€ ํ˜„์žฌ ์ƒํ™ฉ์„ ์•Œ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    terminal ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ’์„ ์ˆ˜์‹ ํ•˜๊ธฐ ์‹œ์ž‘ํ•ด์•ผํ•œ๋‹ค.

    ์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋“  ๊ฐ’์„ ์ „์†ก ์ฆ‰์‹œ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด collect๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

     

    collect๋Š” ์ƒˆ๋กœ์šด ๊ฐ’์ด ์ƒ๊ธธ ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค.

    ์ด๊ฑด suspend ํ•จ์ˆ˜์ด๋ฏ€๋กœ ์ฝ”๋ฃจํ‹ด ๋‚ด์—์„œ ์‹คํ–‰๋˜์–ด์•ผํ•œ๋‹ค.

     

    terminal ํ•จ์ˆ˜๋ฅผ flow์— ์ ์šฉํ•˜๋ฉด ํ•„์š”์— ๋”ฐ๋ผ flow๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ๊ฐ’์„ ์ „์†กํ•˜๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค.

    ๋ฐ˜๋ฉด, intermediate ์—ฐ์‚ฐ์ž๋Š” ์ผ๋ จ์˜ ์—ฐ์‚ฐ์ž๋งŒ ์„ค์ •ํ•˜๋ฉฐ ํ•ญ๋ชฉ์„ flow๋กœ ์ „์†กํ–ˆ์„ ๋•Œ ๊ฐ„๊ฒฉ์„ ๋‘๊ณ  ์—ฐ์‚ฐ์ž๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

     

    userMessage์—์„œ collect๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ flow๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

    ์ƒ์‚ฐ์ž ๋ธ”๋ก์€ ์ •ํ•ด์ง„ ๊ฐ„๊ฒฉ์— ๋”ฐ๋ผ api์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•˜๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค.

     

    ์ฝ”๋ฃจํ‹ด ์šฉ์–ด์—์„œ ์ด๋Ÿฐ ํ”Œ๋กœ๋ฅผ clod flow๋ผ๊ณ  ํ•œ๋‹ค.

    ํ•„์š”์— ๋”ฐ๋ผ ์ƒ์„ฑ๋˜๊ณ  ๊ด€์ฐฐ๋˜๋Š” ์ค‘์—๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค

     

    Flows in Android UI

    Android UI์—์„œ ์ตœ์ ์œผ๋กœ flow๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์ž. ๊ณ ๋ คํ•ด์•ผํ•  ์ ์€ ๋‘๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

    ์ฒซ ๋ฒˆ์งธ๋Š” ์•ฑ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ์žˆ์„ ๋•Œ ๋ฆฌ์†Œ์Šค๋ฅผ ๋‚ญ๋น„ํ•˜์ง€ ์•Š์•„์•ผํ•œ๋‹ค.

    ๋‘ ๋ฒˆ์งธ๋Š” ๊ตฌ์„ฑ ๋ณ€๊ฒฝ๊ณผ ๊ด€๋ จ์ด ์žˆ๋‹ค.

     

    MessagesActivity์—์„œ ํ™”๋ฉด์— ๋ฉ”์‹œ์ง€ ๋ชฉ๋ก์„ ํ‘œ์‹œํ•˜๋ ค ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. 

    ์–ผ๋งˆ๋‚˜ ์˜ค๋ž˜ flow์—์„œ collecting์„ ํ•ด์•ผํ• ๊นŒ?

     

    UI๊ฐ€ ์ ์ ˆํžˆ ๋™์ž‘ํ•˜๊ณ , ํ™”๋ฉด์— UI๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์„ ๋•Œ๋Š” flow์—์„œ ์ˆ˜์ง‘์„ ์ค‘๋‹จํ•ด์•ผํ•œ๋‹ค.

    ๋ฌผ๋กœ ๋น„์œ ๋ฅผ ๋“ค์–ด๋ณด๋ฉด, ํŒ์ตธ๊ฐ€ ์ด๋ฅผ ๋‹ฆ๊ฑฐ๋‚˜ ๋‚ฎ์ž ์„ ์ž˜ ๋•Œ๋Š” ์ˆ˜๋„๊ผญ์ง€๋ฅผ ์ž ๊ฐ€์•ผํ•œ๋‹ค. ํŒ์ตธ๋Š” ๋ฌผ์„ ๋‚ญ๋น„ํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

    UI๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ™”๋ฉด์— ์ •๋ณด๋ฅผ ํ‘œ์‹œํ•˜์ง€ ์•Š์„ ๋•Œ๋Š” flow์—์„œ ์ˆ˜์ง‘ํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค. 

     

    ์—ฌ๊ธฐ์—๋Š” ์—ฌ๋Ÿฌ ์˜ต์…˜์ด ์žˆ๋Š”๋ฐ ๋ชจ๋“  ์˜ต์…˜์ด UI ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ์ธ์‹ํ•œ๋‹ค. ์ˆ˜๋ช… ์ฃผ๊ธฐ ์ฝ”๋ฃจํ‹ด๋ณ„ api๋‚˜ LiveData๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    asLiveData flow ์—ฐ์‚ฐ์ž๋Š” flow๋ฅผ LiveData๋กœ ๋ณ€ํ™˜ํ•ด์„œ UI๊ฐ€ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ๋™์•ˆ์—๋งŒ ํ•ญ๋ชฉ์„ ๊ด€์ฐฐํ•œ๋‹ค.

    ๋ทฐ ๋ชจ๋ธ ํด๋ž˜์Šค์—์„œ๋„ ์ด๋Ÿฐ ๋ณ€ํ™˜์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

     

    ui์—์„œ๋Š” ํ‰์†Œ์ฒ˜๋Ÿผ LiveData๋ฅผ ์†Œ๋น„ํ•œ๋‹ค.

     

    UI ๊ณ„์ธต์—์„œ flow๋ฅผ ์ˆ˜์ง‘ํ•  ๋•Œ repeatOnLifeCycle์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

     

    ์ด๋Š” Lifecycle.State๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š” suspend ํ•จ์ˆ˜์ด๋‹ค.

    ์ด api๋Š” ์ˆ˜๋ช…์ฃผ๊ธฐ๋ฅผ ์ธ์‹ํ•˜๋ฉฐ ์ˆ˜๋ช… ์ฃผ๊ธฐ๊ฐ€ ํ•ด๋‹น ์ƒํƒœ์— ๋„๋‹ฌํ•˜๋ฉด ๋ธ”๋ก์„ ์ „๋‹ฌํ•  ์ƒˆ ์ฝ”๋ฃจํ‹ด์ด ์ž๋™์œผ๋กœ ์‹œ์ž‘๋œ๋‹ค.

    ๊ทธ๋Ÿฌ๋ฉด ์ˆ˜๋ช… ์ฃผ๊ธฐ๊ฐ€ ๊ทธ ์ƒํƒœ ์•„๋ž˜๋กœ ๋–จ์–ด์ง€๋ฉด ์ง„ํ–‰ ์ค‘์ธ ์ฝ”๋ฃจํ‹ด์ด ์ทจ์†Œ๋œ๋‹ค. ๋ธ”๋ก ์•ˆ์ชฝ์€ ์ฝ”๋ฃจํ‹ด ์ปจํ…์ŠคํŠธ์ด๋ฏ€๋กœ collect๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

    repeatOnLifecycle์€ suspend ํ•จ์ˆ˜์ด๋ฏ€๋กœ ์ฝ”๋ฃจํ‹ด์—์„œ ํ˜ธ์ถœํ•ด์•ผํ•œ๋‹ค. 

     

    ์•กํ‹ฐ๋น„ํ‹ฐ ์•ˆ์— ์žˆ์œผ๋ฏ€๋กœ lifecycleScope๋กœ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    ์ˆ˜๋ช…์ฃผ๊ธฐ๊ฐ€ ์ดˆ๊ธฐํ™”๋˜๋ฉด ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด ์•กํ‹ฐ๋น„ํ‹ฐ๋Š” onCreate์—์„œ ํ˜ธ์ถœํ•œ๋‹ค.

    repeatOnLifeCycle์˜ ์ž๋™ํ™” ๋™์ž‘์€ UI ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ์ž๋™์œผ๋กœ ๊ณ ๋ คํ•œ๋‹ค.

    ํŠนํžˆ repeatOnLifeCycle์„ ํ˜ธ์ถœํ•˜๋Š” ์ฝ”๋ฃจํ‹ด์€ ์ˆ˜๋ช…์ฃผ๊ธฐ๊ฐ€ ํŒŒ๊ดด๋  ๋•Œ๊นŒ์ง€ ์‹คํ–‰์„ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.

     

    ์—ฌ๋Ÿฌ flow์—์„œ ์ˆ˜์ง‘ํ•ด์•ผํ•  ๊ฒฝ์šฐ repeatOnLifecycle์—์„œ launch๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ์ฝ”๋ฃจํ‹ด์„ ์ƒ์„ฑํ•ด์•ผํ•œ๋‹ค.

     

    flowWithLifeCycle์—ฐ์‚ฐ์ž๋Š” ์ˆ˜์ง‘ํ•  ํ”Œ๋กœ๊ฐ€ ํ•˜๋‚˜๋ฟ์ผ ๋•Œ repeatOnLifecycle ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

    ์ด api๋Š” ์ˆ˜๋ช…์ฃผ๊ธฐ๊ฐ€ ๋Œ€์ƒ ์ƒํƒœ์—์„œ ๋“ค์–ด๊ฐ€๊ณ  ๋‚˜๊ฐˆ ๋•Œ ํ•ญ๋ชฉ์„ ์ „์†กํ•˜๊ณ  ๊ธฐ๋ณธ ์ƒ์‚ฐ์ž๋ฅผ ์ทจ์†Œํ•œ๋‹ค.

     

     

    ์•กํ‹ฐ๋น„ํ‹ฐ์˜ ์ˆ˜๋ช…์ฃผ๊ธฐ๋ฅผ ์ƒ์„ฑ ์‹œ์ ๋ถ€ํ„ฐ ์•Œ์•„๋ณด์ž. ์‚ฌ์šฉ์ž๊ฐ€ ํ™ˆ๋ฒ„ํŠผ์„ ์ „๋‹ฌํ•˜๋ฉด ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ์ „์†ก๋˜๊ณ  ์•กํ‹ฐ๋น„ํ‹ฐ์—์„œ onStop ์‹ ํ˜ธ๋ฅผ ๋ฐ›๊ณ , onStart๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ์„ ๋•Œ ์•ฑ์„ ๋‹ค์‹œ ์—ฐ๋‹ค.

    repeatOnLifecycle์„ ํ˜ธ์ถœํ•˜๋ฉด UI๊ฐ€ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ๋™์•ˆ flow ์ „์†ก์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์•ฑ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ์ด๋™ํ•˜๋ฉด ์ˆ˜์ง‘์ด ์ทจ์†Œ๋œ๋‹ค.

     

    ์•ˆ๋“œ๋กœ์ด๋“œ UI์—์„œ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ flow๋ฅผ ์ˆ˜์ง‘ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

    lifecycleScope์—์„œ ์‹œ์ž‘ํ•œ ์ฝ”๋ฃจํ‹ด์—์„œ ๋ฐ”๋กœ ์ˆ˜์ง‘ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋Ÿฐ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด๋„ ๋˜์ง€๋งŒ ์ด๋Ÿฐ ๋ฐฉ์‹์˜ ์ˆ˜์ง€๋ธกใ„ด ์œ„ํ—˜ํ•˜๋‹ค.

    flow์—์„œ ์ˆ˜์ง‘ํ•˜๊ณ  UI ์š”์†Œ๋ฅผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค. ์•ฑ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ์žˆ์–ด๋„ ๋งˆ์ฐฌ๊ฐ€์ง€

     

    ํ™”๋ฉด์— ui๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์„ ๋•Œ๋Š” ์šฐ๋ฆฌ๋„ ํ”Œ๋กœ์—์„œ ์ˆ˜์ง‘ํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

     

    lifecycleScope.launch์—์„œ ์ง์ ‘ ์ˆ˜์ง‘ํ•˜๋Š” ๊ฒฝ์šฐ ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ์žˆ์„ ๋„ ๊ณ„์† ํ”Œ๋กœ ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐ›๋Š”๋‹ค. ์ด๋Š” ๋‚ญ๋น„์ด๊ณ  ์œ„ํ—˜ํ•˜๋‹ค.

    ์•ฑ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์ผ ๋Œ€ ๋Œ€ํ™”์ƒ์ž๋ฅผ ํ‘œ์‹œํ•˜๋ฉด ์ถฉ๋Œ์ด ์ผ์–ด๋‚œ๋‹ค.

     

     

    ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด onStart์—์„œ ์ˆ˜๋™์œผ๋กœ ์ˆ˜์ง‘์„ ์‹œ์ž‘ํ•˜๊ณ  onStop์—์„œ ์ˆ˜์ง‘์„ ์ค‘๋‹จํ•ด์•ผํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  repeatOnLifecycle์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๊ฐ€ ์ œ๊ฑฐ๋œ๋‹ค.

     

    launchWhenStarted๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด lifecycleScope.launch๋ณด๋‹ค ๋‚ซ๋‹ค.

    ์•ฑ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ์žˆ์„ ๋•Œ flow ์ˆ˜์ง‘์„ ์ค‘๋‹จํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.  ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฐฉ๋ฒ•์€ flow ์ƒ์„ ์ž๋ฅผ ๊ณ„์† ํ™œ์„ฑํ™”์‹œ์ผœ์„œ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜์ง€ ์•Š์„ ํ•ญ๋ชฉ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ฑ„์šธ ์ˆ˜ ์žˆ๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํ•ญ๋ชฉ์„ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

     

    UI์—์„œ ํ”Œ๋กœ ์ƒ์‚ฐ์ž์˜ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ์•Œ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ repeatOnLifecycle์ด๋‚˜ flowWithLifecycle์„ ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. UI๊ฐ€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ์žˆ์„ ๋•Œ ํ•ญ๋ชฉ์„ ์ˆ˜์ง‘ํ•˜๊ธฐ ์•Š๊ณ  ํ”Œ๋กœ ์ƒ์‚ฐ์ž๋ฅผ ์‚ด๋ ค๋‘”๋‹ค.

     

    ์ด๋ ‡๊ฒŒ ์•ฑ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ์žˆ์„ ๋•Œ ํ”Œ๋กœ ์ˆ˜์ง‘์„ ์ตœ์ ํ™”ํ•  ๊ฒฝ์šฐ ์•ฑ์—์„œ ๊ตฌ์„ฑ ๋ณ€๊ฒฝํ•  ๋•Œ์˜ ๋ช‡ ๊ฐ€์ง€ ์š”๋ น์„ ์•Œ์•„๋ณด์ž

     

    ํ”Œ๋กœ๋ฅผ ๋ทฐ์— ๋…ธ์ถœํ•˜๋ฉด ์ˆ˜๋ช… ์ฃผ๊ธฐ๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ์š”์†Œ ์‚ฌ์ด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฑธ ๊ณ ๋ คํ•ด์•ผํ•œ๋‹ค. ๋ชจ๋“  ์ˆ˜๋ช… ์ฃผ๊ธฐ๊ฐ€ ํ•ด๋‹นํ•˜๋Š” ๊ฑด ์•„๋‹ˆ๋‹ค. ์•กํ‹ฐ๋น„ํ‹ฐ์˜ ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ์ˆ˜๋ช…์ฃผ๊ธฐ๋Š” ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ๋‹ค. 

     

     

    ๊ธฐ๊ธฐ๊ฐ€ ํšŒ์ „๋˜์—ˆ๊ฑฐ๋‚˜ ๊ตฌ์„ฑ ๋ณ€๊ฒฝ์„ ์ˆ˜์‹ ํ•˜๋ฉด ๋ชจ๋“  ์•กํ‹ฐ๋น„ํ‹ฐ๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์ง€๋งŒ ViewModel์€ ๊ทธ๋ ‡์ง€ ์•Š๋‹ค.

     

    ์ฆ‰, viewModel์—์„œ ๋ชจ๋“  ํ”Œ๋กœ๋ฅผ ๋…ธ์ถœํ•˜๋Š” ๊ฑด ์•„๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด๋Ÿฐ ์ฝœ๋“œ ํ”Œ๋กœ๊ฐ€ ์žˆ๋‹ค.

    ์ฝœ๋“œ ํ”Œ๋กœ๋Š” ์ฒ˜์Œ์œผ๋กœ ์ˆ˜์ง‘๋  ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋Š” ํ•œ๋ฒˆ ํšŒ์ „ ํ›„ ๋‹ค์‹œ ๋…ธ์ถœ๋œ๋‹ค.

     

    ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๊ฐ€ ๋ญ์ง€ ?

     

     

     

    ์šฐ๋ฆฌ์—๊ฒŒ๋Š” ๋ฒ„ํผ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๊ด€ํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ ์—ฌ๋Ÿฌ ์ปฌ๋ ‰ํ„ฐ ์‚ฌ์ด์— ๊ณต์œ ํ•˜๋ฉด ๋œ๋‹ค. ์žฌ์ƒ์„ฑ ํšŸ์ˆ˜๋Š” ๊ด€๊ณ„์—†๋‹ค.

    ์ด๋Ÿฐ ๋ชฉ์ ์œผ๋กœ StateFlow๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๋‹ค. 

     

    StateFlow๋Š” ๋ฌผ๋กœ ๋น„์œ ํ•˜๋ฉด ๋ฌผํƒฑํฌ์ด๋‹ค. ์ปฌ๋ ‰ํ„ฐ๊ฐ€ ์—†๋”๋ผ๋„ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๊ด€ํ•œ๋‹ค. ์ผํšŒ์„ฑ ์ˆ˜์ง‘์ด ์•„๋‹ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์•กํ‹ฐ๋น„ํ‹ฐ๋‚˜ ํ”„๋ž˜๊ทธ๋จผํŠธ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์•ˆ์ „ํ•˜๋‹ค.

     

    StateFlow์˜ ์—ฌ๋Ÿฌ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๊ณ  ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ”๋ฃจํ‹ด์—์„œ ๊ฐ€๋Šฅํ•˜๋‹ค.

    ํ•˜์ง€๋งŒ ๋ฐ˜์‘ํ˜•์ด๋ผ๊ณ  ํ•˜๊ธฐ๋Š” ์–ด๋ ต๋‹ค.

     

    ํŒ์ตธ๋Š” ๊ฒŒ์ž„์„ ๊ฐœ์„ ํ•˜๋ผ๊ณ  ๋งํ–ˆ์„ ๊ฒƒ์ด๋‹ค. ๋Œ€์‹  ํ”Œ๋กœ๋ฅผ StateFlow๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด StateFlow๊ฐ€ ์—…์ŠคํŠธ๋ฆผ ํ”Œ๋กœ์—์„œ ๋ชจ๋“  ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐ›์•„ ์ตœ์‹  ๊ฐ’์„ ์ €์žฅํ•œ๋‹ค. ์ปฌ๋ ‰ํ„ฐ๊ฐ€ ์—†๊ฑฐ๋‚˜ ๋งŽ์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ทฐ๋ชจ๋ธ์— ์‚ฌ์šฉํ•˜๊ธฐ์— ์ข‹๋‹ค.

    ์—ฌ๋Ÿฌ ์œ ํ˜•์˜ flow๊ฐ€ ์žˆ์ง€๋งŒ StateFlow๋ฅผ ๋งค์šฐ ์ •ํ™•ํ•˜๊ฒŒ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ด๋ฅผ ๊ถŒ์žฅํ•œ๋‹ค.

     

    ํ”Œ๋กœ๋ฅผ StateFlow๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ stateIn ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

    ์„ธ ๊ฐ€์ง€ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›๋Š”๋ฐ,initalValue๋Š” StateFlow์— ํ•ญ์ƒ ๊ฐ’์ด ์žˆ์–ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฝ”๋ฃจํ‹ด ๋ฒ”์œ„๋Š” ๊ณต์œ ๊ฐ€ ์‹œ์ž‘๋˜๋Š” ์‹œ์ ์„ ์ œ์–ดํ•˜๋Š”๋ฐ ์—ฌ๊ธฐ์— ๋ทฐ๋ชจ๋ธ์˜ ๋ฒ”์œ„๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    ๋งˆ์ง€๋ง‰์œผ๋กœ started ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด 2๊ฐ€์ง€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋ณด์ž

     

    ์ฒซ์งธ, ํ”Œ๋กœ์˜ ์ปฌ๋ ‰ํ„ฐ์ธ ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์ผ์ • ์‹œ๊ฐ„ ํŒŒ๊ดด๋˜์—ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์ƒ์„ฑ์‹œํ‚ค๋Š” ํšŒ์ „์ด๋‹ค.

    ๋‘˜์จฐ, ํ™ˆ์œผ๋กœ ์ด๋™ํ•ด์„œ ์•ฑ์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ๋„ฃ๋Š”๋‹ค.

     

    ํšŒ์ „ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ์ตœ๋Œ€ํ•œ ๋น ๋ฅด๊ฒŒ ์ „ํ™˜ํ•˜๋ ค๋ฉด Flow๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

    ๊ทธ๋Ÿฌ๋‚˜ ํ™ˆ์œผ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒฝ์šฐ  ๋ฐฐํ„ฐ๋ฆฌ์™€ ๋‹ค๋ฅธ ๋ฆฌ์†Œ์Šค๋ฅผ ์•„๋ผ๊ธฐ ์œ„ํ•ด ๋ชจ๋“  ํ”Œ๋กœ๋ฅผ ์ค‘๋‹จํ•ด์•ผํ•œ๋‹ค.

     

    ๊ทธ๋Ÿฌ๋ฉด ์–ด๋–ค ์‹œ๋‚˜๋ฆฌ์˜ค์ธ์ง€ ํƒ์ง€ํ•  ์ˆ˜ ์žˆ๋‚˜? ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

    StateFlow์˜ ์ˆ˜์ง‘์ด ์ค‘๋‹จ๋˜์—ˆ์„ ๋•Œ ๋ชจ๋“  ์—…์ŠคํŠธ๋ฆผ ํ”Œ๋กœ๋ฅผ ์ฆ‰์‹œ ์ค‘๋‹จํ•˜๋Š” ๊ฑด ์•„๋‹ˆ๋‹ค. ์˜คํžˆ๋ ค ์•ฝ 5์ดˆ์ •๋„๋ฅผ ์ž ์‹œ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

    ์‹œ๊ฐ„ ์ดˆ๊ณผ์ „์— ํ”Œ๋กœ๋ฅผ ์ˆ˜์ง‘ํ•˜๋ฉด ์—…์ŠคํŠธ๋ฆผ ํ”Œ๋กœ๊ฐ€ ์ทจ์†Œ๋˜์ง€ ์•Š๋Š”๋‹ค.

     

     

    WhileSubscribed(5000)์ด ๋ฐ”๋กœ ๊ทธ๋Ÿฐ ์ผ์„ ํ•œ๋‹ค.

     

    ์ด ํ‘œ์—๋Š” ์•ฑ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ๊ฐ”์„ ๋•Œ ๋ฐ˜์‘์ด ๋‚˜์™€์žˆ๋‹ค. ํ™ˆ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ธฐ ์ „์— ๋ทฐ๊ฐ€ ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  StateFlow๋Š” ์ •์ƒ์ ์œผ๋กœ ์—…์ŠคํŠธ๋ฆผ ํ”Œ๋กœ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด์ œ ๋ทฐ๊ฐ€ ์ค‘๋‹จ๋˜๋ฉด ์ปฌ๋ ‰์…˜์ด ์ฆ‰์‹œ ์ข…๋ฃŒ๋œ๋‹ค.  

    ๊ทธ๋Ÿฌ๋‚˜ StateFlow๋Š” ๊ตฌ์„ฑ ๋ฐฉ๋ฒ•์œผ๋กœ ์ธํ•ด ์—…์ŠคํŠธ๋ฆผ ํ”Œ๋กœ๋ฅผ ์ค‘๋‹จํ•˜๋Š”๋ฐ 5์ดˆ๊ฐ€ ๊ฑธ๋ฆฐ๋‹ค. ์ œํ•œ ์‹œ๊ฐ„์ด ์ง€๋‚ฌ๊ณ  ์—…์ŠคํŠธ๋ฆผ ํ”Œ๋กœ๋Š” ์ทจ์†Œ๋œ๋‹ค. 

     

    ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์„ ๋‹ค์‹œ ์—ด ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ ์—…์ŠคํŠธ๋ฆผ ํ”Œ๋กœ๊ฐ€ ๋‹ค์‹œ ์‹œ์ž‘๋œ๋‹ค.  

    ๊ทธ๋Ÿฌ๋‚˜ ํšŒ์ „ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ๋ทฐ๋Š” ์ž ์‹œ๋งŒ ์ค‘๋‹จ๋œ๋‹ค. ์–ด์จ‹๋“  5์ดˆ์ด๋‚ด์ด๋‹ค. 

    ๋”ฐ๋ผ์„œ StateFlow๋Š” ์ ˆ๋Œ€ ๋ณต์›ํ•˜์ง€ ์•Š๊ณ  ๋ชจ๋“  ์—…์ŠคํŠธ๋ฆผ ํ”Œ๋กœ๋ฅผ ํ™œ์„ฑ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๋ฉฐ ์•„๋ฌด์ผ๋„ ์—†์—ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ์‚ฌ์šฉ์ž์—๊ฒŒ ํšŒ์ „ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณด๋‚ธ๋‹ค.

     

    ์ฆ‰ ๋‹ค์‹œ ๋งํ•ด StateFlow๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ทฐ๋ชจ๋ธ์—์„œ ํ”Œ๋กœ๋ฅผ ๋…ธ์ถœํ•˜๊ฑฐ๋‚˜ asLiveData๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ด์™€ ๋™์ผํ•œ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒŒ ์ข‹๋‹ค.

     

    Testing Flows

    ๋‘ ๊ฐ€์ง€ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์žˆ๋‹ค.

    ์ฒซ ๋ฒˆ์งธ๋Š” ํ…Œ์ŠคํŠธ ๋Œ€์ƒ์ด ๋ฌด์—‡์ด๋“  UUT๊ฐ€ ํ”Œ๋กœ๋ฅผ ๋ฐ›๋Š”๋‹ค. ์ข…์†์„ฑ์„ ๊ฐ€์ƒ ์ƒ์‚ฐ์ž๋กœ ๊ต์ฒดํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒŒ ํŽธ๋ฆฌํ•˜๋‹ค.

     

    ์˜ˆ๋ฅผ ๋“ค์–ด ์ด ๊ฐ€์ƒ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•˜์—ฌ ๊ฐ ํ…Œ์ŠคํŠธ ์‚ฌ๋ก€์— ํ•„์š”ํ•œ ๊ฑธ ์ „์†กํ•  ์ˆ˜ ์žˆ๋‹ค.

    ๊ฐ„๋‹จํ•œ ์ฝœ๋“œ ํ”Œ๋กœ์˜ ์˜ˆ๋ฅผ ๋“ค์–ด๋ณด์ž. ํ…Œ์ŠคํŠธ ์ž์ฒด๋Š” ํ…Œ์ŠคํŠธ ์•„๋ž˜ ์ฃผ์ œ์˜ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ์–ด์„ค์…˜์„ ๋งŒ๋“ ๋‹ค. ์ด๋Š” ํ”Œ๋กœ๋‚˜ ๋‹ค๋ฅธ ๊ฒŒ ๋  ์ˆ˜ ์žˆ๋‹ค. 

     

     

     

    ๋‘๋ฒˆ์งธ๋Š” UUT๊ฐ€ ํ”Œ๋กœ๋ฅผ ๋…ธ์ถœํ•˜๊ณ  ์ด ๊ฐ’์ด๋‚˜ ๊ฐ’ ์ŠคํŠธ๋ฆผ์„ ์ธ์ฆํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ˆ˜์ง‘ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ 

    ํ”Œ๋กœ์—์„œ first( ) ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ฒซ ํ•ญ๋ชฉ์„ ์ˆ˜์‹ ํ•˜๊ณ  ์ˆ˜์ง‘์„ ์ค‘๋‹จํ•  ๋•Œ๊นŒ์ง€ ๊ณ„ ์ˆ˜์ง‘ํ•œ๋‹ค.

    ๋˜ํ•œ take(5) ์—ฐ์‚ฐ์ž๋กœ toList terminal ์—ฐ์‚ฐ์ž๋ฅผ ํ˜ธ์ถœํ•ด ๋ฉ”์‹œ์ง€๋ฅผ 5๊ฐœ๋งŒ ์ˆ˜์ง‘ํ•œ๋‹ค. 


    ์ผ๋ฐ˜์ ์ธ list ์ถœ๋ ฅ์„ suspend์™€ Flow๋กœ ์ฐจ์ด ์‚ดํŽด๋ณด๊ธฐ 

    ๊ธฐ๋ณธ list ์ถœ๋ ฅ ํ•จ์ˆ˜ 

    fun main() {
    
        foo().forEach { value ->
            println(value)
        }
    
    }
    
    fun foo(): List<Int> = listOf(1, 2, 3)

     

    suspend ํ•จ์ˆ˜๋กœ ๋ณ€๊ฒฝ

    suspend fun foo(): List<Int> {
        delay(1000) // pretend we are doing something asynchronous here
        return listOf(1, 2, 3)
    }
    
    fun main() = runBlocking<Unit> {
        foo().forEach {
            value -> println(value)
        }
    }

     

    flow๋กœ ๋ณ€๊ฒฝ 

    fun foo(): Flow<Int> = flow { // flow builder
        for (i in 1..3) {
            delay(100) // pretend we are doing something useful here
            emit(i) // emit next value
        }
    }
    
    fun main() = runBlocking<Unit> {
    
        // Collect the flow
        foo().collect {
            value -> println(value)
        }
    }

     

    ์ฝ”๋“œ๋กœ ์•Œ์•„๋ณด๊ธฐ

       val chargedMoneyFlow: Flow<Int> = dataStore.data
            .catch {
                exception -> if (exception is IOException) {
                    emit(emptyPreferences())
            } else{
                throw exception
            }
            }
            .map { preferences ->
                preferences[PreferencesKeys.CHARGED_MONEY] ?: 0 }

     

     ์ด ์ฝ”๋“œ๋Š” datastore๊ณผ coroutine์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž”์•ก ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š” ๋น„๋™๊ธฐ์ ์ธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

    chargedMoneyFlow๋Š” ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ์—์„œ ๊ฐ€์ ธ์˜จ ์ •์ˆ˜๊ฐ’์„ ํ‘œํ˜„ํ•˜๋Š” Flow์ด๋‹ค.

     

    ๋™์ž‘์„ ์ •๋ฆฌํ•ด๋ณด๋ฉด 

    datStore.data๋ฅผ ํ†ตํ•ด dataStore์— ๊ฐ’์„ ์ฝ์–ด์˜ค๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” flow๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

     

    ์–ด๋–ป๊ฒŒ dataStore.data๋ฅผ ํ†ตํ•ด flow๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ๊ณ ์‹ถ๋‹ค๋ฉด? 

    ๋”๋ณด๊ธฐ
    ๋”๋ณด๊ธฐ

    dataStore.data๋ฅผ ์‚ดํŽด๋ณด๋ฉด ๋ฐ˜ํ™˜๊ฐ’์ด Flow<T>์ด๋‹ค. 

    dataStore.data๋Š” DataStore์—์„œ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ์‚ฌ์šฉ๋˜๊ณ  ๋ฐ˜ํ™˜๋œ๋ฐ์ดํ„ฐ๋Š” Flow๋กœ ํ‘œํ˜„๋œ๋‹ค

    ๋”ฐ๋ผ์„œ ์ด Flow๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ์˜ ๋ณ€ํ™”๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ  ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. 

     

     

     

    map์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ’์„ Preferences.CHARGED_MONEY ํ‚ค์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

     ์ด ๋•Œ ๋งŒ์•ฝ ์ด ํ‚ค์— ๋Œ€์‘ํ•˜๋Š” ๊ฐ’์ด ์—†๋‹ค๋ฉด ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ 0์„ ์‚ฌ์šฉํ•œ๋‹ค.

     .map { preferences ->
                preferences[PreferencesKeys.CHARGED_MONEY] ?: 0 }

     

    .map ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š”?

    ๋”๋ณด๊ธฐ
    ๋”๋ณด๊ธฐ

    ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜๋•Œ๋ฌธ์ด๋‹ค.

    ์ด ๋ถ€๋ถ„์€ chargedMoneyFlow์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€ํ™˜ํ•˜์—ฌ ์ตœ์ข…์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ํ˜•ํƒœ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. 

    chargedMoneyFlow๋Š” datastore์—์„œ ๊ฐ€์ ธ์˜จ ์„ค์ • ๊ฐ’์— ๋Œ€ํ•œ flow์ด๋‹ค. 

     

    preferences๋Š” chargedMoneyFlow์—์„œ ๋ฐฉ์ถœ๋œ ๋ฐ์ดํ„ฐ ์ฆ‰, datastore์—์„œ ๊ฐ€์ ธ์˜จ ๊ฐ’์„ ๋‚˜ํƒ€๋‚ด๋ฉด,

    ์ด ๊ฐ’์€ PreferencesKeys.CHARGED_MONEY์— ํ•ด๋‹นํ•˜๋Š” value๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. 

     

    1๏ธโƒฃ preferences[PreferencesKeys.CHARGED_MONEY] ๋ฅผ ํ†ตํ•ด์„œ charged_money ํ‚ค์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค.

    2๏ธโƒฃ ํ•ด๋‹นํ•˜๋Š” ํ‚ค๊ฐ€ ์—†๋‹ค๋ฉด 0์„ ์‚ฌ์šฉํ•œ๋‹ค. 

     

    dataStore.data๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ datastore์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ค๋Š” ๋กœ์ง์ด๋‹ค. 

    ์ถ”๊ฐ€๋กœ .catch๋ฅผ ํ†ตํ•ด ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ๊ณ , IOException์ธ ๊ฒฝ์šฐ์—๋Š” emptyPreferences( )๋ฅผ emit ํ•ด์ฃผ์—ˆ๋‹ค.

     

     

     

    ๊ณต๋ถ€ํ•œ ์ž๋ฃŒ 

    https://philosopher-chan.tistory.com/1546

     

    Coroutine flow

    ์ฝ”๋ฃจํ‹ด์˜ flow ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ผ๋‹จ ๊ตฌ๊ธ€ ๋ฌธ์„œ๋ถ€ํ„ฐ ํ•œ๋ฒˆ ์‚ดํŽด๋ณผ๊นŒ์š”? ์ฝ”๋ฃจํ‹ด์—์„œ ํ๋ฆ„์€ ๋‹จ์ผ ๊ฐ’๋งŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ •์ง€ ํ•จ์ˆ˜์™€ ๋‹ฌ๋ฆฌ ์—ฌ๋Ÿฌ ๊ฐ’์„ ์ˆœ์ฐจ์ ์œผ๋กœ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” ์œ ํ˜•์ž…๋‹ˆ๋‹ค. ์˜ˆ

    philosopher-chan.tistory.com

    https://developer.android.com/kotlin/flow?hl=ko

     

    Android์˜ Kotlin ํ๋ฆ„  |  Android Developers

    Android์˜ Kotlin ํ๋ฆ„ ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•˜๊ธฐ ๋‚ด ํ™˜๊ฒฝ์„ค์ •์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถ„๋ฅ˜ํ•˜์„ธ์š”. ์ฝ”๋ฃจํ‹ด์—์„œ ํ๋ฆ„์€ ๋‹จ์ผ ๊ฐ’๋งŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ •์ง€ ํ•จ์ˆ˜์™€ ๋‹ฌ๋ฆฌ ์—ฌ๋Ÿฌ ๊ฐ’์„ ์ˆœ์ฐจ์ ์œผ๋กœ ๋‚ด๋ณด๋‚ผ

    developer.android.com

     

    728x90