๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Android & Kotlin

Lesson 5: App Architecture(UI Layer)

5. What is Architecture

Application Architecture๋ž€ ์•ฑ์˜ ํด๋ž˜์Šค๋“ค์— ๋Œ€ํ•œ ๋””์ž์ธ๊ณผ ๊ทธ๋“ค ์‚ฌ์ด์˜ ๊ด€๊ณ„. 
์•ฑ์„ ๊ตฌ์„ฑํ•˜๋Š”๋ฐ ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•๋งŒ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ง‘์„ ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ์€ ์ƒํ™ฉ, ํ•„์š”, ์ทจํ–ฅ ๋“ฑ์— ๊ฐ•ํ•œ ์˜์กด์„ฑ์„ ๋ˆ๋‹ค. 
์ด์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ๋„ ๋‹ค์–‘ํ•œ ์„ค๊ณ„ ์Šคํƒ€์ผ์ด ์žˆ๋‹ค. ๋˜ ๊ฐ ๋ฐฉ์‹์€ ์žฅ๋‹จ์ ์ด ์žˆ๋‹ค. ์„œ๋กœ๊ฐ€ ๊ณตํ†ต์ ์„ ๊ฐ–๊ธฐ๋„ ํ•œ๋‹ค. ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์•ฑ์˜ ํ•„์š”๋‚˜ ํŒ€์˜ ํฌ๊ธฐ, ํŒ€์˜ ์„ฑํ–ฅ ๋“ฑ์— ๋”ฐ๋ผ ์ ํ•ฉํ•œ ์Šคํƒ€์ผ์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค. 
์ด๋ฒˆ lesson์—์„œ๋Š” a single multipurpose architectural pattern์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ MVVM๊ณผ ๋น„์Šทํ•˜๋‹ค. 

6. Our App Architecture

Software design principle
- Separation of concerns: Divide your code into classes, each with separate, well defined responsibilities. 

Architecture๋Š” ์–ด๋Š ํด๋ž˜์Šค๊ฐ€ ์–ด๋–ค ์—ญํ• ์„ ํ•ด์•ผํ•˜๋Š”์ง€ figure out ํ•˜๊ธฐ์œ„ํ•ด ๊ฐ€์ด๋“œ๋ผ์ธ์„ ์ค€๋‹ค. 

LiveData๋Š” ViewModel๊ณผ UIController ๊ฐ„์— ์ •๋ณด๋ฅผ ๊ต๋ฅ˜ํ•˜๋Š”๋ฐ ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค. communicating update and redraw the screen.

7. ViewModel

์•ฑ์˜ UI ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” abstract class ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  configuration changes๋ฅผ ์ƒ์กดํ•œ๋‹ค. 

ViewModel์ด ์œ ์šฉํ•œ ์ด์œ ๋Š” ๋ฌด์—‡์ธ๊ฐ€?

์Šคํฌ๋ฆฐ์„ ํšŒ์ „ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ configuration change๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด activity์™€ ๋‚ด๋ถ€์— ์žˆ๋Š” ๋ชจ๋“  fragments๋Š” ํŒŒ๊ดด๋˜๊ณ  OS์— ์˜ํ•ด์„œ rebuild ๋˜๋Š”๋ฐ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด์„œ ์˜ฌ๋ฐ”๋ฅธ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฐ์ดํ„ฐ๋Š” ์‚ฌ๋ผ์ ธ๋ฒ„๋ฆฐ๋‹ค. ์•ž์—์„œ onSaveInstanceState๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ดค์ง€๋งŒ ์ €์žฅํ•ด์•ผํ•  ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ๋‹ค๋ฉด ์ข‹์€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์•„๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ViewModel์ด ๋„์ž…๋œ๋‹ค.

UI ๋ฐ์ดํ„ฐ๋ฅผ Fragment์— ๋‘์ง€ ์•Š๊ณ  ViewModel์— ๋‘”๋‹ค. ๊ทธ๋ฆฌ๊ณ  fragment๊ฐ€ ViewModel์— ๋Œ€ํ•œ reference๋ฅผ ๊ฐ–๋Š”๋‹ค. ViewModel์€ Configuration changes๋ฅผ ์ƒ์กดํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— fragment๊ฐ€ ํŒŒ๊ดด๋˜๊ณ  ๋‹ค์‹œ ๋งŒ๋“ค์–ด์ง€๋Š” ๋™์•ˆ์—๋„ ๋ชจ๋“  fragment์— ๋ณด์—ฌ์ ธ์•ผํ•˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ViewModel์— ๋‚จ์•„์žˆ๋‹ค. ๋‹ค์‹œ ์ƒ์„ฑ๋œ fragment๋ฅผ ๋™์ผํ•œ ViewModel์— ์—ฐ๊ฒฐํ•ด์ค€๋‹ค๋ฉด ๋ฐ์ดํ„ฐ๋Š” ๊ทธ๋Œ€๋กœ ์žˆ๋‹ค! 

10. Exercise: Populate the GameViewModel

ViewModel vs. UI Controller

  • ViewModel holds data for UI
  • UI Controller only displays and gets user/OS events.
    (Should have as little responsibility as possible, ํ™”๋ฉด์— ๊ทธ๋ฆฌ๊ณ  input ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€) 
  • UI Controller does NOT make decisions.
    UI Controller๋Š” views๋ฅผ instantiateํ•˜๊ณ  containํ•œ๋‹ค. 
  • ViewModel should never contain references to activities, fragments or views. 
    Why? ์šฐ๋ฆฌ๊ฐ€ ViewModel์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด๋ณด๋ผ. ViewModel์ด configuration changes๋ฅผ ์‚ด์•„๋‚จ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 
    ๋ณธ๋ž˜ acitivity, fragment and view๋Š” configuration changes ์—์„œ ์‚ด์•„๋‚จ์„ ์ˆ˜ ์—†๋‹ค. 

Why ViewModel should never contain references to activities, fragments or views?

ViewModel์—์„œ configuration changes๋กœ ๋” ์ด์ƒ ํ™”๋ฉด์— ๋ณด์—ฌ์ง€์ง€ ์•Š๋Š” acitivity, view, fragment์— ๋Œ€ํ•œ reference๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด clean up ๋˜์–ด์•ผํ•˜๋Š” reference๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. 
Best case scenario์—์„œ๋Š” ์‚ฌ์†Œํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์ด์ง€๋งŒ, worst case scenario์—์„œ๋Š” ์Šคํฌ๋ฆฐ์— ์—†๋Š” old fragment๋กœ ๋ฌด์–ธ๊ฐ€๋ฅผ ํ•˜๋ ค๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— error๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. 

11. The Benefit of a Good Architecture

์ด ๋””์ž์ธ์˜ ๋‹ค๋ฅธ ๋ถ€๋ฉด์œผ๋กœ code๊ฐ€ modularํ•˜๋‹ค๋Š” ๊ฒƒ์ธ๋ฐ, UI Controller๋Š” ViewModel์— ๋Œ€ํ•ด์„œ ์•Œ์ง€๋งŒ ViewModel์€ UI Controller์— ๋Œ€ํ•ด์„œ ๋ชจ๋ฅธ๋‹ค.

์ด architecture์˜ ๋ชฉํ‘œ ์ค‘ ํ•˜๋‚˜๋Š” class ๊ฐ„์— reference์˜ ์ˆ˜๋ฅผ ์ ๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋˜ ๋‹ค๋ฅธ ์ธก๋ฉด ๋ฐ ์œ ์ต์€ ViewModel์ด activity๋‚˜ fragments, views์— ๋Œ€ํ•ด reference๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ด๊ฒƒ์€ testing ์‹œ์— ์œ ์šฉํ•˜๋‹ค. ํ”„๋กœ์ ํŠธ์—๋Š” 2๊ฐ€์ง€ Test๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ android Test(์—๋ฎฌ๋ ˆ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ)์™€ Test(์—๋ฎฌ๋ ˆ์ดํ„ฐ๊ฐ€ ํ•„์š”์—†๋Š”)์ด๋‹ค. ViewModel์— ๋Œ€ํ•œ reference๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— pure lightweight ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋ ˆ์ž„์›Œํฌ์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ์œ ๋‹› ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ ํ•  ์ˆ˜ ์žˆ๊ณ  ๋”ฐ๋ผ์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š”๋ฐ์— ๋” ๋น ๋ฅด๊ณ  ์‰ฝ๋‹ค. 

- organized: the code is more organized, manageable, and debuggable
- easier to debug: protect yourself from having to worry about lifecycle problems and bugs. 
- fewer lifecycle issues
- modular: easier to swap out and update sections of code
- testable

13. LiveData

LiveData: An observable data holder class that is lifecycle-aware

 

LiveData ๋‚ด๋ถ€์— ์‹ธ์—ฌ์žˆ๋Š” Data๊ฐ€ ๋ฐ”๋€Œ๋ฉด state๊ฐ€ ๋ณ€ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค. 

15. Lifecycle Awareness

  • LiveData will only update UI Controllers that are actually on-screen
    - If your fragment goes off-screen and the value of LiveData changes, it would not update the off-screen fragment. If UI Controller is off-screen, it gets no updates. 
  • If UI Controller comes back on-screen, get the current data immediately
  • If UI Controller observes, it gets the current data immediately
  • If UI Controller is destroyed, it cleans up the connection. 

16. Exercise: Add LiveData Encapsulation to GameViewModel

์บก์Šํ™”(Encapsulation): The notion of restricted direct access to the object's fields. ์™ธ๋ถ€์—์„œ ๋‚ด๋ถ€์˜ ๊ฐ’์„ ์‰ฝ๊ฒŒ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์—ฌ๋Ÿฌ ๋ฒ„๊ทธ๋ฅผ ์•ผ๊ธฐํ•  ๊ฒƒ. ๋ฒ„๊ทธ๋ฅผ ์ฐพ๊ธฐ๋„ ์–ด๋ ค์›Œ์ง. 

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•
๋‚ด๋ถ€์—๋Š” mutableLiveData, ์™ธ๋ถ€์—๋Š” LiveData. Kotlin backing property๋ผ๊ณ  ๋ถ€๋ฆ„. It allows you to return something from a getter other than the exact object. 

22. Exercise: Add a ViewModelFactory

ViewModelFactory: A class that knows how to create ViewModels. Factories are classes that knows how to initiate object. 

'Android & Kotlin' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Overloading / Overriding  (0) 2022.03.02
Lesson 6: App Architecture (Persistence)  (0) 2022.02.23
๊ณต๋ถ€ ์ฃผ์ œ  (0) 2022.02.19
Lesson 4: Activity & Fragment Lifecycle  (0) 2022.02.11
Lesson 3: App Navigation  (0) 2022.02.08