Notice
Recent Posts
Recent Comments
Link
ยซ   2025/04   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags
more
Archives
Today
Total
๊ด€๋ฆฌ ๋ฉ”๋‰ด

๐ŸŒฑ dreaming DiNO

[Android] MVVM ๋ณธ๋ฌธ

Android

[Android] MVVM

MK_____ 2021. 11. 11. 15:02

MVVM - Model, View, ViewModel

MVVM ์˜ ๊ฐœ๋…์˜ ๊ธฐ์ดˆ๋Š” PM(Presentation Model - ๋งˆํ‹ดํŒŒ์šธ๋Ÿฌ์˜ ์ œ์•ˆ)์˜ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด ์กŒ๋‹ค. PM ์€ View์— ๋ Œ๋”๋ง์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐœ์ฒด์ด๊ณ , View ๋Š” PM ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ Œ๋”๋งํ•œ๋‹ค. PM ์˜ ์ค‘์š”ํ•œ ํฌ์ธํŠธ๋Š” PM ์ด ๋“ค๊ณ  ์žˆ๋Š” ๋ฐ์ดํ„ฐ์™€ View๋Š” ํ•ญ์ƒ ๋™๊ธฐํ™”๊ฐ€ ๋˜์–ด์•ผํ•œ๋‹ค๋Š” ๊ฒƒ. ์—ฌ๊ธฐ์„œ ํ›„์— PM ์„ ViewModel ์ด๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ช…๋ช…ํ•˜๋ฉด์„œ MVVM์ด ํƒ„์ƒํ–ˆ๋‹ค.

์ „์ฒด ์ž‘์—…์„ UI ๋กœ์ง ์ž‘์—… ๊ณผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ž‘์—…์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋‚˜๋ˆ„์–ด์ง„ ์ž‘์—…์„ ๋””์ž์ธ์— ํŠนํ™”๋œ UI ๊ฐœ๋ฐœ์ž๋Š” UI์ชฝ์„ ๋‹ด๋‹นํ•˜๊ณ , ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ํŠนํ™”๋œ ๊ฐœ๋ฐœ์ž๋Š” ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์„ ๋‹ด๋‹นํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋‚˜๋‰˜์–ด์žˆ๋‹ค.

MVVM์€ Model, View, ViewModel์˜ ์•ฝ์ž์ด๊ณ  ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • View
    • ํ™”๋ฉด์— ํ‘œํ˜„๋˜๋Š” ๋ ˆ์ด์•„์›ƒ์— ๋Œ€ํ•ด ๊ด€์—ฌ.
    • ๊ธฐ๋ณธ์ ์œผ๋กœ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ ๋ฐฐ์ œ ํ•˜์ง€๋งŒ UI ๊ด€๋ จ๋œ ์ผ๋ถ€ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
      • ์‚ฌ๋žŒ๋“ค ๋งˆ๋‹ค ์˜๊ฒฌ์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๊ณ , ‘์•ˆ๋“œ๋กœ์ด๋“œ ๋‚ด๋ถ€์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ฟŒ๋ฆฌ๋Š” ๊ธฐ๋Šฅ๋งŒ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค’ ๋ผ๋Š” ์˜๊ฒฌ์„ ๊ฐ€์ง„ ์ด๋„ ์žˆ๋‹ค.
    • ViewModel ์„ ๊ด€์ฐฐํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ์ „๋‹ฌ๋˜๋ฉด ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•ด์•ผํ•œ๋‹ค.
  • ViewModel
    • View์— ์—ฐ๊ฒฐ ํ•  ๋ฐ์ดํ„ฐ์™€ ๋ช…๋ น์œผ๋กœ ๊ตฌ์„ฑ. ๋ณ€๊ฒฝ ์•Œ๋ฆผ์„ ํ†ตํ•ด View์— ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. ๊ทธ์— ๋”ฐ๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ํ™”๋ฉด์— ๋ฐ˜์˜ ํ•˜๋Š” ์—ฌ๋ถ€๋Š” View๊ฐ€ ํƒํ•˜๋„๋ก ํ•˜๋ฉฐ ๋ช…๋ น์€ UI ๋ฅผ ํ†ตํ•ด์„œ ๋™์ž‘ํ•˜๋„๋ก ํ•œ๋‹ค.
    • ๋น„๋™๊ธฐ ์ž‘์—… ํ†ตํ•ด UI์˜ ์‘๋‹ต์„ฑ์„ ์œ ์ง€. ์‚ฌ์šฉ์ž์˜ ์„ฑ๋Šฅ ์ธ์‹ ๊ธฐ๋Šฅ์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด UI ์Šค๋ ˆ๋“œ๋ฅผ ์ฐจ๋‹จ ํ•ด์ œ ๋œ ์ƒํƒœ๋กœ ์œ ์ง€ํ•ด์•ผํ•œ๋‹ค. View Model ์—์„œ I/O ์ž‘์—…์— ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ View์˜ ์†์„ฑ๋ณ€๊ฒฝ์„ ์•Œ๋ฆฐ๋‹ค.
    • View Model ๊ณผ Model ์‚ฌ์ด์—๋Š” ์ผ๋Œ€ ๋‹ค ๊ด€๊ณ„๊ฐ€ ์žˆ์œผ๋ฉฐ ViewModel์€ View์˜ ์ปจํŠธ๋กค์ด ์ง์ ‘ data binding ์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก View ์— Model ํด๋ž˜์Šค๋ฅผ ์ง์ ‘ ๋…ธ์ถœ ํ•˜๋„๋ก ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” Model ์€ data binding์„ ์ง€์›ํ•˜๊ณ  notification even ๋ฅผ ๋ณ€๊ฒฝ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋””์ž์ธ ๋˜์•ผํ•œ๋‹ค.
    • AAC(Android Architecture Component) ์˜ ViewModel ์€ LifeCycle ์„ ๊ณ ๋ คํ•˜์—ฌ UI ๊ด€๋ จ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋„๋ก ์„ค๊ณ„๋œ๋‹ค. ViewModel ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ™”๋ฉด ํšŒ์ „๊ณผ ๊ฐ™์ด ๊ตฌ์„ฑ์„ ๋ณ€๊ฒฝํ•  ๋•Œ๋„ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • Andorid ์—์„œ MVVM ์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•œ๋‹ค๋ฉด, ๋ฐ˜๋“œ์‹œ AAC ์˜ ViewModel ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๊ตฌํ˜„์€ ๊ฐ€๋Šฅํ•˜๋‹ค.
    • View์˜ ์ƒํƒœ์™€ ํ–‰๋™์ด ์ถ”์ƒํ™” ๋œ๊ฒƒ.
    • View์˜ input๊ณผ output์ด ๋ช…์‹œ๋˜์–ด ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค
    • ์ˆœ์ˆ˜ํ•จ์ˆ˜ ์ฒ˜๋Ÿผ ๊ฐ™์€ ๊ฐ’์˜ input์—๋Š” ํ•ญ์ƒ ๊ฐ™์€ ๊ฐ’์˜ output์ด ๋ฐ˜ํ™˜๋˜์–ด์•ผํ•จ
    • output์€ View์˜ ์ƒํƒœ์™€ Route๋กœ ๋‚˜๋‰จ
  • Model
    • App ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์บก์Šํ™” ํ•˜๋Š” ๋น„์‹œ๊ฐ์  ํด๋ž˜์Šค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์•ก์„ธ์Šค ํ•˜๊ฑฐ๋‚˜ ์บ์‹ฑ์ด ํ•„์š”ํ•œ ์„œ๋น„์Šค ๋˜๋Š” ๋ ˆํฌ์ง€ ํ† ๋ฆฌ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋œ๋‹ค.
    • ViewModel ์—์„œ data๋ฅผ ๊ฐ€์ ธ๊ฐˆ ์ˆ˜ ์žˆ๊ฒŒ ์ค€๋น„ํ•˜๊ณ , ๊ทธ์—๋Œ€ํ•œ event ๋ฅผ ๋ณด๋‚ธ๋‹ค.

View ์€ ViewModel ์„ ์•Œ์ง€๋งŒ ViewModel ์€ View๋ฅผ ์•Œ ์ˆ˜ ์—†๊ณ ,
ViewModel์€ Model์„ ์•Œ์ง€๋งŒ Model์€ ViewModel์„ ๋ชฐ๋ผ์•ผํ•œ๋‹ค.

MVVM ์€ MVP ์™€ ๋ฐ˜๋Œ€๋กœ View ๊ฐ€ ๋Šฅ๋™์ ์ด๋‹ค. View ๊ฐ€ ์Šค์Šค๋กœ ViewModel ๊ฐ์ฒด์˜ ์–ด๋–ค ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ์ง€ ์ง์ ‘์ ์œผ๋กœ ๊ด€์ฐฐํ•œ๋‹ค. ๊ด€์ฐฐ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ViewModel ์˜ ๋ฐ์ดํ„ฐ๋Š” ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ํ˜•ํƒœ์—ฌ์•ผํ•œ๋‹ค.

LiveData, ObservableField ๊ฐ์ฒด(Google) ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, Observable ๊ฐ์ฒด(RxJava)๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

๋ณ€ํ™”๊ฐ€ ์ƒ๊ธฐ๋ฉด ์ฆ‰์‹œ View๋Š” ์•Œ๋ฆผ์„ ๋ฐ›๊ณ , ์•Œ๋งž์€ View ๋ Œ๋”๋ง ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

Google์—์„œ ์ œ์•ˆํ•œ ์˜ˆ์ œ์—์„œ๋Š” 2๊ฐ€์ง€ ํ˜•ํƒœ๋กœ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

  • ViewModel ๋‚ด๋ถ€์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ํ˜ธ์ถœ
    • MVP ์™€ ๋™์ผํ•œ ๋ฐฉ๋ฒ•
    • ๋ณ„๋„์˜ ์ธํ„ฐํŽ˜์ด์Šค๋‚˜ ํด๋ž˜์Šค ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์œ„์ž„ํ•˜๋Š” ๊ฒƒ์ด ๋กœ์ง์„ ๋ถ„๋ฆฌํ•˜๋Š” ์ธก๋ฉด์—์„œ ๋ฐ”๋žŒ์ง
  • ViewModel ๋‚ด๋ถ€์— ์žˆ๋Š” CommandObservable ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœ
    • View์—์„œ ๋ฐœ์ƒํ•œ Action์„ ์ „๋‹ฌ๋งŒ ํ•  ๋ฟ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ฒ˜๋ฆฌ๋Š” ํ•ด๋‹น CommandObservable์„ ๊ด€์ฐฐํ•˜๋Š” ์ชฝ์—์„œ ๋‹ด๋‹นํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ข€ ๋” ๊ฐ•์ œ๋กœ ๋ถ„๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ํ•˜์ง€๋งŒ CommandObservable์„ ๊ด€์ฐฐํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ ViewModel ์ž์‹ ์ด๋ผ๋ฉด ๊ทธ๊ฒƒ์€ ๋ถˆํ•„์š”ํ•œ ๊ด€์ฐฐ์ด ๋  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— CommandObservable์„ ์‚ฌ์šฉ ํ•œ๋‹ค๋ฉด ViewModel ์ด ์•„๋‹Œ ๋‹ค๋ฅธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ฒ˜๋ฆฌ ๊ฐ์ฒด๊ฐ€ ๊ด€์ฐฐ์„ ํ•˜๋„๋ก ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•˜๋‹ค.

MVC ์™€ MVVM ์˜ ์ฐจ์ด๋Š” ๊ทธ๋ฆผ ํ•œ์žฅ์ด๋ฉด ์ถฉ๋ถ„ํ•  ๊ฒƒ ๊ฐ™์•„์„œ ๊ฐ€์ ธ์™”๋‹ค.

MVVM ์œผ๋กœ ๊ฐœ๋ฐœ์‹œ์—๋Š” Databinding ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ์„ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ํ•œ๋‹ค. View์˜ dependency ๋ฅผ Activity, Fragment ์˜์กด์—์„œ xml ์˜์กด์œผ๋กœ ๋‚ด๋ฆด ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹ค์Œ์˜ ๊ทธ๋ฆผ์œผ๋กœ ํ‘œํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

View๋Š” ์‹ค์ œ XML ๋งŒ ์กด์žฌํ•˜๋ฉฐ View์— ์ฝ”๋“œ์ ์œผ๋กœ ์ ‘๊ทผํ•  ์ผ์ด ์žˆ๋‹ค๋ฉด BindingAdapter ์™€ InverseBindingAdapter ๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•˜๊ณ , ์ƒํƒœ๊ฐ’์„ ํ†ตํ•ด View๋ฅผ ๊ฐฑ์‹ ํ•œ๋‹ค. ViewModel ์€ View์— ํ‘œํ˜„ํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋“ค๊ณ  ์žˆ์œผ๋ฉด์„œ MVP ์˜ Presenter์™€ ๊ฐ™์ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ View ์‚ฌ์ด์˜ ์ค‘์žฌ์ž ์—ญํ• ์„ ํ•œ๋‹ค.

ViewModel ๋‚ด๋ถ€์—๋Š” observable ํ•„๋“œ๋“ค์„ ์ •์˜ํ•˜๊ณ , View์˜ Action์„ ๋ฐ›์„ interface ๋˜๋Š” CommandObservable ๊ฐ์ฒด๋ฅผ ๋ฏธ๋ฆฌ ์ •์˜ํ•˜๋ฉด ๋œ๋‹ค. ViewModel ์—์„œ ๋ฏธ๋ฆฌ ์ •์˜๋œ ๊ฐ’์„ xml ์—์„œ observing ํ•˜๊ณ  ํ•„์š”ํ•œ View์˜ Action ์„ ํ˜ธ์ถœํ•˜๋„๋ก ๋งŒ๋“ค๋ฉด ๋ถ„๋ฆฌ๋œ ์˜์—ญ ๋‚ด์—์„œ ์„œ๋กœ ๋ถ€๋”ชํžˆ์ง€ ์•Š๊ณ  ์ž‘์—…์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ฐ ๋ชจ๋“ˆ๊ฐ„์˜ ์˜์กด์„ฑ์ด ๋‚ฎ๊ธฐ์— ๊ฐ์ž์˜ ํŒŒํŠธ์—์„œ ๊ฐœ๋ฐœ์ด ๊ฐ€๋Šฅํ•˜๋Š”๋ฐ ๋ถˆํŽธํ•จ์ด ์ค„์–ด๋“ ๋‹ค.

  • UI ๊ฐœ๋ฐœ์ž๋Š” xml, BindingAdapter, InverseBindingAdapter๋งŒ ๊ฐœ๋ฐœ
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋‹ด๋‹น์ž๋Š” ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์„ ๊ฐœ๋ฐœ

MVP ์—์„œ๋Š” ์˜์—ญ๋ถ„๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅ์€ ํ•˜์ง€๋งŒ ์ถฉ๋Œ ์˜์—ญ์ด ์ƒ๊ธด๋‹ค. View๋Š” Presenter ๋ฅผ , Presenter๋Š” View ๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž‘์—… ์˜์—ญ์ด ๊ฒน์น˜๊ณ  ํ•ด๋‹น ๋ถ€๋ถ„์—์„œ ์ถฉ๋Œ์ด ๋ฐœ์ƒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

databinding ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด, xml ์ด ๋””์ž์ธ ์š”์†Œ ๋ฐฐ์น˜๋ฅผ ๋‹ด๋‹นํ•  ๋ฟ ์•„๋‹ˆ๋ผ, ViewModel ์„ ํ†ตํ•ด data ์—ฐ๊ฒฐ๊ณผ ์ด๋ฒคํŠธ ์ „๋‹ฌ์˜ ์—ญํ• ์„ ํ•œ๋‹ค.

ํŠน์ • View์— ์–ด๋–ค ๋ฐ์ดํ„ฐ๊ฐ€ ๋งคํ•‘๋˜๋Š”์ง€ xml์ƒ์—์„œ ๋ฐ”๋กœ ์ž…๋ ฅ์ด ๊ฐ€๋Šฅํ•˜๊ณ , observe ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋นŒ๋“œ์‹œ ์•Œ์•„์„œ observe ํ•จ์ˆ˜๋ฅผ ์ž๋™ ์ƒ์„ฑํ•œ๋‹ค. MVP ๋‚˜ ๊ธฐ์กด์˜ ๋ฐฉ๋ฒ•์œผ๋กœ ๋งคํ•‘ ํ•˜๋ ค๋ฉด ๊ฐ๊ฐ์˜ View ์— id ๋ฅผ ๋ถ€์—ฌํ•˜๊ณ  ํ•ด๋‹น View ๋ฅผ findViewById ๋“ฑ์œผ๋กœ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„์—, ๋ฐ์ดํ„ฐ ์„ธํŒ…ํ•ด์•ผํ•˜๋Š”๋ฐ, databinding ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์•„์ด๋”” ์—†์ด๋„ ์•Œ์•„์„œ ๋งคํ•‘์‹œํ‚จ๋‹ค.

MVVM ์˜ ์žฅ์ 

  • ViewModel ์ด model ์˜ ์–ด๋Œ‘ํ„ฐ ์—ญํ• ์„ ํ•˜์—ฌ model ์˜ ์ฃผ์š”ํ•œ ์ฝ”๋“œ ๋ณ€๊ฒฝ์„ ๋ฐฉ์ง€ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ฐœ๋ฐœ์ž๋Š” View๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ViewModel ๋ฐ Model ์— ๋Œ€ํ•œ Unit ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ณ , ViewModel ์— ๋Œ€ํ•œ Unit ํ…Œ์ŠคํŠธ๋Š” View ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ์ •ํ™•ํ•˜๊ฒŒ ๋™์ผํ•œ ๊ธฐ๋Šฅ ์‹คํ–‰์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. -> UI, ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง, DB ๋“ค์ด ๊ธฐ๋Šฅ๋ณ„๋กœ ๋ชจ๋“ˆํ™”๊ฐ€ ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ
  • ์™„์ „ํ•˜๊ฒŒ ์ƒˆ๋กญ๊ฒŒ ๊ตฌ์„ฑ๋˜๋Š” UI๋ฅผ ๋‹ค์‹œ ๋””์ž์ธ ํ•˜์—ฌ๋„ ์ฝ”๋“œ๋ฅผ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๊ณ  ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“ค์–ด์ง„ View ์—์„œ๋„ ๊ธฐ์กด์˜ ViewModel ๊ณผ ๋™์ผํ•œ ๊ธฐ๋Šฅ์ด ์ˆ˜ํ–‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  • UI ๊ฐœ๋ฐœ์ž์™€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ๊ฐ์˜ ๋ถ„๋ฆฌ๋˜์–ด ๋™์‹œ์— ์ž‘์—…์ด ๊ฐ€๋Šฅํ•˜๋‹ค.๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ฐœ๋ฐœ์ž๊ฐ€ ViewModel ๊ณผ Model ์˜ ์š”์†Œ์—์„œ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์„ ๋•Œ UI ๊ฐœ๋ฐœ์ž๋Š” View์—๋งŒ ์ง‘์ค‘ํ•˜์—ฌ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ViewModel ์„ ํ†ตํ•ด data ๋ฅผ ์ฐธ์กฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— Activity, Fragment ์˜ ์ƒ๋ช…์ฃผ๊ธฐ์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค. ๋˜ํ•œ View๊ฐ€ ํ™œ์„ฑํ™” ๋˜์–ด์žˆ์„ ๊ฒฝ์šฐ์—๋งŒ ์ž‘๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆํ•„์š”ํ•œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.
  • ViewModel๊ณผ View๊ฐ€ ์ผ ๋Œ€ ๋‹ค ์—ฐ๊ฒฐ์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ViewModel ์˜ ๋ฉ”์†Œ๋“œ๋ฅผ A-Activity, B-Activity ๋“ฑ ์—ฌ๋Ÿฌ View์—์„œ ํ˜ธ์ถœํ•ด ์žฌ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธํ•˜๋‹ค. ์‚ฌ์‹ค ํ•ด๋‹น ๊ตฌ์กฐ๋Š” ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๊ฒฝ์šฐ์˜ ์ˆ˜๊ฐ€ ๊ทนํžˆ ์ ๋‹ค.
  • binding๋˜๋Š” ์‹œ์ ์— ๋ชจ๋“  input์— ๋Œ€ํ•œ output์„ ์‚ฐ์ถœํ•˜๋Š” ๋กœ์ง์ด ์ •ํ•ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ์ž๊ฐ€ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•ด์•ผํ•˜๋Š” ์œ„ํ—˜์„ ์ค„์—ฌ์ค€๋‹ค.
  • Databinding์„ ํ†ตํ•ด ์ˆ˜๋งŽ์€ ๋ณด์ผ๋Ÿฌ ํ”Œ๋ ˆ์ดํŠธ ์ฝ”๋“œ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

๋‹จ์ 

  • xml ๋‚ด๋ถ€์—์„œ ์ค‘๊ด„ํ˜ธ ์•ˆ์— ์„ ์–ธํ•˜๋Š” ๊ตฌ๋ฌธ์„ ๋ณ„๋„์˜ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๋ถˆํŽธํ•จ์ด ์ƒ๊ธด๋‹ค. ํŠน์ • observing ํ•„๋“œ๋ฅผ ์—ฌ๋Ÿฌ View์—์„œ ์ฐธ์กฐํ•˜๋Š” ๊ฒฝ์šฐ ์ด ํ•„๋“œ๋ฅผ ์ฐธ์กฐํ•˜๋Š” View ๋“ค์„ ์ฐพ๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰์„ ์ˆ˜๋™์œผ๋กœ ํ•ด์•ผํ•œ๋‹ค.
  • ๋˜ํ•œ Xml escaping ์—์„œ ๋ถˆํŽธํ•จ์„ ๋Š๋‚Œ ์ˆ˜ ์žˆ๋‹ค. xml ์—์„œ๋Š” <, > ๋ฌธ์ž๊ฐ€ ํ—ˆ์šฉ ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— &lt; &gt; ํ˜•์‹์œผ๋กœ ์จ์•ผํ•œ๋‹ค.
  • ๊ธฐ์กด์— ๋น„ํ•ด ์ถ”๊ฐ€๋กœ ๋งŒ๋“ค์–ด ์ฃผ์–ด์•ผ ํ•˜๋Š” ํด๋ž˜์Šค๋„ ๋งŽ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์—ฐ๊ฒฐํ•ด์ฃผ์–ด์•ผํ•˜๊ณ  ํ•ด๋‹น ๊ณผ์ •์ด ๋ณต์žกํ•ด์ง€๋ฉด cost ๊ฐ€ ๋งŽ์ด ํ•„์š”๋กœ ํ•  ์ˆ˜ ์žˆ๋‹ค.

XML ์— ์ •์˜ํ•œ View ์—์„œ ๋ฐœ์ƒํ•œ ์ด๋ฒคํŠธ๋„ ์ผ๋ฐ˜์ ์œผ๋กœ ViewModel์„ ๋งค๊ฐœ๋กœ ์ด๋ฃจ์–ด์ง€๋ฉฐ ๋ฐฉ๋ฒ•์€ ํฌ๊ฒŒ 3๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

  • ViewModel ์ง์ ‘ ํ˜ธ์ถœ ๋ฐฉ์‹
app:onRefreshListener="@{viewmodel::onRefresh}"
app:refreshing="@{viewmodel.dataLoading}"

android:onClick="@{() -> viewmodel.addNewTask()}"=

ViewModel์€ ์˜ต์ €๋น™ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๊ด€ํ•˜๋Š” ์šฉ๋„๊ฐ€ ์ฃผ์š” ์—ญํ• ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ ‡๊ฒŒ ๋ฉ”์„œ๋“œ๋ฅผ ViewModel ์— ๋„ฃ๋Š” ๋ฐฉ์‹์€ ์ง€์–‘ํ•˜๋Š”๊ฒŒ ์ข‹๋‹ค. ViewModel์— ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์ง์ ‘์ ์œผ๋กœ ๋“ค์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ๋Š” ๊ฐ ํ™”๋ฉด์ด ํ•ด๋‹น ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ํŠนํ™”๋˜๊ณ , ํ•ด๋‹น ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ๋‹ค๋ฅธ ๊ณณ์—์„œ ์“ฐ์ด์ง€ ์•Š์•„์•ผ ์„ค๊ณ„์ ์œผ๋กœ ์˜๋ฏธ๊ฐ€ ์žˆ๋‹ค.

  • Observing Command Field๋ฅผ ํ†ตํ•œ ๋ฐฉ์‹
    • Add Command Observing Field
    val snackbarMessage = SingleLiveEvent<Int>()
    val newTaskEvent = SingleLIveEvent<Void>()
    
    • Observe Field
    newTaskEvent.observe(this@Activity, Observer<Void>{
    	this@Activity.addNewTask()
    })
    
    • Invoke Field
    fun addNewTask(){
    	newTaskEvent.call()
    }
    

โ€‹ Observing Command ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ์œ„์™€ ๊ฐ™์ด 3๊ฐ€์ง€ ๋‹จ๊ณ„๋ฅผ ๋Š˜ ์ž‘์„ฑํ•ด์ฃผ์–ด์•ผํ•œ๋‹ค.

  • ๊ด€์ฐฐ ํ•„๋“œ ์„ ์–ธ
  • ๋กœ์ง ์ˆ˜ํ–‰๋ถ€์—์„œ ๊ด€์ฐฐ
  • ํ•„๋“œ๋ฅผ invoke ์‹œ์ผœ Observer ๋“ค์—๊ฒŒ ์•Œ๋ ค์ค€๋‹ค.
  • ๊ธฐ์กด MVP ์—์„œ๋Š” ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ๊ทธ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰๋งŒ ํ•˜๋ฉด ๋์ง€๋งŒ, ํ•ด๋‹น ๋ฐฉ์‹์€ ํ•จ์ˆ˜์™€ ํ•จ์ˆ˜ ์‹คํ–‰ ์‚ฌ์ด์— 3๊ฐ€์ง€ ์ผ์ด ์ถ”๊ฐ€๋œ๋‹ค. ๊ด€์ฐฐ ํฌ์ธํŠธ๋ฅผ ๋‘๋Š” ๊ฒƒ์ด ๊น”๋”ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์€ 1๊ณณ์—์„œ๋งŒ ํ•„์š”๋กœ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๊ฐ€ ๋Š˜์–ด๋‚˜๋Š” ๋ถ€๋ถ„์— ์žˆ์–ด ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ํž˜๋“ค ์ˆ˜ ์žˆ๋‹ค.
  • ๋ณ„๋„์˜ Listener๋ฅผ ํ†ตํ•œ ๋ฐฉ์‹์œ„์™€ ๊ฐ™์ด ๋ณ„๋„์˜ Listener๋ฅผ ๋‘๊ฒŒ ๋˜๋ฉด ViewModel ์—์„œ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ ๋–ผ์–ด ๋‚ผ ์ˆ˜ ์žˆ์–ด ์ข‹์€ ์ ์ด ์žˆ๋‹ค. Listener์˜ ์‹ค์ œ ๊ตฌํ˜„์€ Binding์ด ์ผ์–ด๋‚˜๋Š” ๊ณณ์—์„œ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š”๋ฐ, ๊ทธ ๊ณณ์ด ๋งŒ์•ฝ Activity ๋‚˜ Fragment๋ผ๋ฉด ํ•ด๋‹น ํด๋ž˜์Šค์— ๋น„์ง€๋‹ˆ์Šค๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ๋ณด๋‹ค๋Š”, ๋ณ„๋„์˜ ๋ถ„๋ฆฌ๋œ ํด๋ž˜์Šค๋กœ ์œ„์ž„ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  • listener = object : TaskDetailUserActionsListener{
    	override. fun onCompleteChanged(v : View){
    		viewmodel?.setCompleted((v as CheckBox).isChecked)
    	}
    }
    

 

์ถœ์ฒ˜ : https://jjjoonngg.github.io/android%20architecture/MVVM/