Seize the day

POST : Android Dev Study

ViewModel 초기화

https://developer.android.com/kotlin/ktx#fragment 이쪽 코드를 보다가 생성자가 있는 ViewModel의경우 Factory를 만들어야하는 것이 좀 거슬려서 factoryPorducer를 viewModelProducer로 바꿔서 수정해 봤다. 

package com.mdiwebma.base.kotlin_ext

import androidx.activity.ComponentActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStore

class ViewModelLazy<ViewModelType : ViewModel>(
    private val viewModelClass: Class<ViewModelType>,
    private val storeProducer: () -> ViewModelStore,
    private val viewModelProducer: (() -> ViewModelType)? = null
) : Lazy<ViewModelType> {
    private var cached: ViewModelType? = null
    override val value: ViewModelType
        get() {
            val viewModel = cached
            return if (viewModel == null) {
                val factory = if (viewModelProducer != null) {
                    object : ViewModelProvider.Factory {
                        @Suppress("UNCHECKED_CAST")
                        override fun <T : ViewModel> create(modelClass: Class<T>): T {
                            return viewModelProducer.invoke() as T
                        }
                    }
                } else {
                    ViewModelProvider.NewInstanceFactory()
                }
                val store = storeProducer()
                ViewModelProvider(store, factory).get(viewModelClass).also {
                    cached = it
                }
            } else {
                viewModel
            }
        }

    override fun isInitialized() = cached != null
}

inline fun <reified ViewModelType : ViewModel> ComponentActivity.viewModel(
    noinline viewModelProducer: (() -> ViewModelType)? = null
): Lazy<ViewModelType> = ViewModelLazy(
    ViewModelType::class.java,
    { viewModelStore },
    viewModelProducer
)

inline fun <reified ViewModelType : ViewModel> Fragment.viewModel(
    noinline viewModelProducer: (() -> ViewModelType)? = null
): Lazy<ViewModelType> = ViewModelLazy(
    ViewModelType::class.java,
    { viewModelStore },
    viewModelProducer
)

inline fun <reified ViewModelType : ViewModel> Fragment.activityViewModel(
    noinline viewModelProducer: (() -> ViewModelType)? = null
): Lazy<ViewModelType> = ViewModelLazy(
    ViewModelType::class.java,
    { requireActivity().viewModelStore },
    viewModelProducer
)

 

사용할 때는 

// 생성자가 있는 viewModel
private val vm: TestViewModel by viewModel { TestViewModel(intent.toString()) }

// 생성자가 없는 ViewModel
private val vm: TestViewModel by viewModel()

// Activity의 viewModel
private val vm: TestViewModel by activityViewModel()

 

조금 개선.. lazy 말고 바로 getViewModel 로 즉시 생성할 수도 있게

class InternalViewModelFactory<ViewModelType : ViewModel>(
    private val viewModelProducer: (() -> ViewModelType)
) : ViewModelProvider.Factory {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return viewModelProducer() as T
    }
}

inline fun <reified ViewModelType : ViewModel> ComponentActivity.viewModel(
    noinline viewModelProducer: (() -> ViewModelType)? = null
) = lazy {
    getViewModel(viewModelProducer)
}

inline fun <reified ViewModelType : ViewModel> ComponentActivity.getViewModel(
    noinline viewModelProducer: (() -> ViewModelType)? = null
) = ViewModelProvider(
    this,
    if (viewModelProducer != null) InternalViewModelFactory(viewModelProducer)
    else ViewModelProvider.NewInstanceFactory()
).get(ViewModelType::class.java)


inline fun <reified ViewModelType : ViewModel> Fragment.viewModel(
    noinline viewModelProducer: (() -> ViewModelType)? = null
) = lazy {
    getViewModel(viewModelProducer)
}

inline fun <reified ViewModelType : ViewModel> Fragment.getViewModel(
    noinline viewModelProducer: (() -> ViewModelType)? = null
) = ViewModelProvider(
    this,
    if (viewModelProducer != null) InternalViewModelFactory(viewModelProducer)
    else ViewModelProvider.NewInstanceFactory()
).get(ViewModelType::class.java)

inline fun <reified ViewModelType : ViewModel> Fragment.activityViewModel(
    noinline viewModelProducer: (() -> ViewModelType)? = null
) = lazy {
    getActivityViewModel(viewModelProducer)
}

inline fun <reified ViewModelType : ViewModel> Fragment.getActivityViewModel(
    noinline viewModelProducer: (() -> ViewModelType)? = null
) = ViewModelProvider(
    requireActivity(),
    if (viewModelProducer != null) InternalViewModelFactory(viewModelProducer)
    else ViewModelProvider.NewInstanceFactory()
).get(ViewModelType::class.java)
top

posted at

2020. 4. 6. 04:52


CONTENTS

Seize the day
BLOG main image
김대정의 앱 개발 노트와 사는 이야기
RSS 2.0Tattertools
공지
아카이브
최근 글 최근 댓글
카테고리 태그 구름사이트 링크