Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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
- recyclerview
- View
- activity
- hilt
- 알림
- 알고리즘
- kotlin
- notification
- CoordinatorLayout
- Coroutine
- DataBinding
- AppBarLayout
- Algorithm
- lifecycle
- room
- sqlite
- Navigation
- LiveData
- CustomView
- onMeasure
- onLayout
- BOJ
- 안드로이드
- HTTP
- CollapsingToolbarLayout
- 백준
- 코틀린
- ViewModel
- Behavior
- Android
Archives
- Today
- Total
개발일지
Android in A..Z - Lifecycle (ViewModel) 본문
ViewModel
Android Jetpack의 구성요소이며 UI관련 데이터를 관리하도록 설계되었습니다. UI관련 Data를 Activity, Fragment와 분리시켜 관리하면서 많은 이점을 얻을 수 있습니다.
장점
- Android에서 Activity와 Fragment의 수명주기를 관리하기 때문에 Android에서 UI 컨트롤러를 제거하거나 다시 만드는 경우 데이터가 삭제되지만 ViewModel은 독립된 수명주기를 가지기 떼문에 데이터를 유지할 수 있습니다.
- UI관련 Data를 비동기적인 호출로 받아올 때 메모리 누수를 신경쓰거나, 비동기 호출을 관리하는 코드가 필요하거나 UI 컨트롤러가 변경될 경우 이미 호출한 코드를 다시 호출해야하는 경우가 생길 수 있지만 ViewModel을 재사용하면서 이러한 불편함을 해소할 수 있습니다.
- UI 컨트롤러 로직과 데이터 관련 코드를 분리하면서 유지보수를 쉽게 할 수 있습니다.
Dependency
def lifecycle_version = "2.2.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// Navigation
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.2'
예제
화면 회전시 Android에서 Activity를 재생성하기 때문에 UI관련 데이터가 삭제되지만 ViewModel을 사용시 데이터를 유지할 수 있다.
MainActivity
class MainActivity : BaseActivity<ActivityMainBinding>(R.layout.activity_main) {
// 생성자가 필요한 ViewModel 사용하는 코드. (ViewModelProvider.Factory 사용하면 된다.)
// private val model by viewModels<ChronometerViewModel> { ChronometerViewModelFactory(3000L) }
private val model by viewModels<ChronometerViewModel>()
private val recordAdapter by lazy { RecordAdapter() }
private fun onResetChronometer() {
model.state.value = ChronometerViewModel.State.RESET
model.sumOfTickTime = 0L
binding.chronometer.base = SystemClock.elapsedRealtime()
val count = model.recordList.size
model.recordList.clear()
recordAdapter.notifyItemRangeRemoved(0, count)
}
private fun onStartChronometer() {
model.state.value = ChronometerViewModel.State.START
val tickTime = SystemClock.elapsedRealtime()
model.lastTickTime = tickTime
binding.chronometer.base = SystemClock.elapsedRealtime() - model.sumOfTickTime
onRunChronometer()
}
private fun onRunChronometer() {
model.state.value = ChronometerViewModel.State.RUN
}
private fun onResumeChronometer() {
model.state.value = ChronometerViewModel.State.RESUME
val tickTime = SystemClock.elapsedRealtime()
model.lastTickTime = tickTime
binding.chronometer.base = SystemClock.elapsedRealtime() - model.sumOfTickTime
onRunChronometer()
}
private fun onStopChronometer() {
model.state.value = ChronometerViewModel.State.STOP
binding.chronometer.base = SystemClock.elapsedRealtime() - model.sumOfTickTime
}
override fun init() {
super.init()
initChronometer()
initViewModel()
initStartButton()
initStopButton()
initResumeButton()
initResetButton()
initRecordButton()
initRecyclerView()
}
private fun initViewModel() {
with(model) {
state.observe(this@MainActivity) {
binding.state = it
when(it ?: ChronometerViewModel.State.RESET) {
ChronometerViewModel.State.RUN -> {
binding.chronometer.start()
}
ChronometerViewModel.State.RESET -> {
binding.chronometer.stop()
}
ChronometerViewModel.State.STOP -> {
binding.chronometer.stop()
}
else -> {
}
}
}
}
}
private fun initChronometer() {
with(binding.chronometer) {
base = SystemClock.elapsedRealtime() - model.sumOfTickTime
setOnChronometerTickListener {
val tickTime = SystemClock.elapsedRealtime()
model.sumOfTickTime += tickTime - model.lastTickTime
model.lastTickTime = tickTime
}
}
}
private fun initResetButton() {
binding.setOnReset {
onResetChronometer()
}
}
private fun initStartButton() {
binding.setOnStart {
onStartChronometer()
}
}
private fun initStopButton() {
binding.setOnStop {
onStopChronometer()
}
}
private fun initResumeButton() {
binding.setOnResume {
onResumeChronometer()
}
}
private fun initRecordButton() {
binding.setOnRecord {
with(model) {
recordList.add(Record(recordList.size.toLong(), sumOfTickTime))
recordAdapter.notifyItemInserted(recordList.size - 1)
}
}
}
private fun initRecyclerView() {
with(binding.recyclerView) {
adapter = recordAdapter
recordAdapter.submitList(model.recordList)
}
}
}
ChronometerViewModel
class ChronometerViewModel(initialTime: Long = 0L) : ViewModel() {
var sumOfTickTime = initialTime
var lastTickTime = 0L
val recordList by lazy { ArrayList<Record>() }
val state by lazy { MutableLiveData(State.RESET) }
enum class State {
RESET, START, RUN, STOP, RESUME
}
}
ChronometerViewModelFactory
class ChronometerViewModelFactory(private val initialTime: Long) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return ChronometerViewModel(initialTime) as T
}
}
Git (예제코드)
github.com/KangTaeJong98/Example/tree/main/Android/LifeCycle
'Android (안드로이드) > Lifecycle' 카테고리의 다른 글
Android in A..Z - Lifecycle (Scope) (0) | 2021.03.24 |
---|---|
Android in A..Z - Lifecycle (ViewModel with SavedStateHandle) (0) | 2021.03.20 |
Android in A..Z - Lifecycle (LiveData) (0) | 2021.02.06 |
Android in A..Z - Lifecycle (ViewModelProvider) (0) | 2021.02.01 |
Comments