728x90

https://developer.android.com/topic/libraries/architecture/viewmodel 에 잘 설명되어 있다.

ViewModel 를 사용하는 가장 큰 이유는 UI 와 로직의 분리이다.

액티비티, 프래그먼트 생명주기에 종속되지 않게 할 수 있다는 점이 가장 큰 매력이다.

실행되는 앱을 가로모드, 세로모드로 변경하면 값이 초기화되는데 ViewModel 을 사용하면 값이 유지된다.

 

ViewModel에는 onCleared() 함수가 존재한다.

 

jetpack LiveData

Observer에게 데이터 변경에 대한 알림을 보내는 클래스이다.

계속해서 데이터를 관찰하고 업데이트되기 때문에 UI 와 데이터간에 일치성을 가진다는 장점을 가지고 있다.

 

ViewModel 에서 context나 activity객체를 사용하고 싶다면 AndroidViewModel() 사용해야 한다.

 

여러 유투브 동영상을 보고 "개발하는 정대리" https://www.youtube.com/watch?v=-b0VNKw_niY 강좌가 간단하면서도 개념 이해하는데 도움이 되는 거 같아서 이걸 보면서 연습한 코드를 적어둔다.

동영상 강좌 중에 ViewModelProvieders.of(this).get(~~) 이런식으로 설명한 코드가 있는데 테스트 해보니

ViewModelProviders는 deprecated 되었더라. 그러므로 ViewModelProvider를 사용해줘야 한다.

 

앱 build.gradle 추가사항

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
android {
    buildFeatures { // 뷰 바인딩 사용하겠다.
        viewBinding true
    }
}
 
dependencies {
 
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.5.0'
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
 
    // 뷰모델 (ViewModel)
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
    // 라이브 데이터(LiveData) - 옵저버 패턴 관련 - 데이터의 변경 사항을 알 수 있다.
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
}

 

MainViewModel.kt

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
 
enum class ActionType {
    PLUS, MINUS
}
 
// 데이터의 변경 : 뷰모델은 데이터의 변경 사항을 알려주는 라이브 데이터를 가지고 있음
class MainViewModel : ViewModel() {
 
    companion object{
        const val TAG: String = "로그"
    }
 
    // 뮤터블 라이브 데이터 - 수정 가능
    // 라이브 데이터 - 값 변경 안됨
 
    // 내부에서 설정하는 자료형은 뮤터블로 변경가능하도록 설정
    private val _currentValue = MutableLiveData<Int>()
 
    // 변경되지 않는 데이터를 가져올 때 이름을 _언더스코어 없이 설정
    // 공개적으로 가져오는 변수는 private 이 아닌 public으로 외부에서도 접근 가능하도록 설정
    // 하지만 값을 직접 라이브데이터에 접근하지 않고 뷰모델을 통해 가져올 수 있도록 설정
    val currentValue: LiveData<Int>
        get() = _currentValue
 
    // 초기값 설정
    init {
        Log.d(TAG, " MainViewModel - 생성자 호출")
        _currentValue.value = 0
    }
 
    fun updateValue(actionType: ActionType, input: Int){
        when(actionType){
            ActionType.PLUS ->
                _currentValue.value = _currentValue.value?.plus(input)
            ActionType.MINUS ->
                _currentValue.value = _currentValue.value?.minus(input)
        }
 
    }
}

 

MainActivity.kt

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
31
32
33
34
35
36
37
38
39
40
41
42
43
class MainActivity : AppCompatActivity(), View.OnClickListener {
 
    companion object{
        const val TAG: String = "로그"
    }
 
    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
 
    // 나중에 값이 설정될 것이라고 lateinit 으로 설정
    lateinit var mainViewModel: MainViewModel
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //setContentView(R.layout.activity_main)
        setContentView(binding.root) // View Bindg 과정
 
        // 뷰 모델 프로바이더를 통해 뷰모델 가져오기
        mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
        // 뷰모델이 가지고 있는 값의 변경사항을 관찰할 수 있는 라이브 데이터를 관찰한다
        mainViewModel.currentValue.observe(this, Observer {
            Log.d(TAG,"MainActivity - mainViewModel - CurrentValue 라이브 데이터 값 변경 : $it")
            binding.tvNumber.text = it.toString()
        })
 
        // 리스너 연결
        binding.btnPlus.setOnClickListener(this)
        binding.btnMinus.setOnClickListener(this)
    }
 
    override fun onClick(view: View?) {
        val userInput: Int  = binding.etNumber.text.toString().toInt()
 
        // ViewModel 에 LiveData 값을 변경하는 메소드
        when(view){
            binding.btnPlus ->
                mainViewModel.updateValue(actionType = ActionType.PLUS, userInput)
            binding.btnMinus ->
                mainViewModel.updateValue(actionType = ActionType.MINUS, userInput)
        }
 
    }
}
 

 

내 GitHub 에 올린 전체 소스 코드

https://github.com/jsk005/KotlinProjects/tree/master/viewmodel

블로그 이미지

Link2Me

,