当工厂不再存在时ViewModel初始化

问题描述 投票:0回答:1

我正在使用

by viewModels
机制在 MainActivity 中创建一个最小的 ViewModel。

它目前仅通过依赖注入维护一个存储库。 这需要构造参数,因此我提供了一个工厂类来执行此操作。

我在

MainActivity
中实例化一个 Factory 对象,并使用
by viewModels
传递相同的对象来初始化该 ViewModel 的第一个也是唯一一个实例。

private val Context.dataStore by preferencesDataStore("settings")

class MainActivity : AppCompatActivity() {

//..
    private val viewModel : AutomationViewModel by viewModels {
        AutomationViewModelFactory(
        this.application, SettingsRepository(dataStore))
    }
//...

ViewModel 看起来像这样:

class AutomationViewModel(
    private val mApplication: Application, // not really needed.
    private val repository: SettingsRepository
): ViewModel() {

    // example property to setup an observable state
    val loginParametersState: StateFlow<LoginParameters> =
        repository.LoginParametersFlow.stateIn(
            viewModelScope,
            SharingStarted.Eagerly, LoginParameters()
        )

    // This is the dummy method, that seems to be necessary to 
    //    preheat.
    var dummy: Int = 0; private set
    fun setDummy(x: Int) {
        dummy = x
    }

}

这是关联的工厂类

class AutomationViewModelFactory(
    private val mApplication: Application, // not really needed
    private val repository: SettingsRepository
) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return when(modelClass) {
            AutomationViewModel::class.java -> AutomationViewModel(mApplication, repository)
            else -> throw IllegalArgumentException("Unknown ViewModel class")
        } as T
    }

// Not sure what this is about
    override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
        return super.create(modelClass, extras)
    }

然后在我的一个片段中使用

AutomationViewModel
,也使用
by viewModels
机制。当然,我的想法是利用之前缓存的已经实例化的实例
AutomationViewModel

在我的 Fragments 上,我使用相同的“by”机制获取 ViewModel 对象。 但是,我此时不会传递 Factory 对象,因为它现在超出了范围,其范围仅限于 Activity。

class LoginFragment : Fragment() {
    private val connector: AutomationViewModel by activityViewModels()

    //.. Usual boilerplate code for onCreate, onCreateView, onViewCreated. Nothing particular to see there.


    }

无论如何,我不想在 Fragment 中使用工厂对象,因为我无权访问它,并且不想最终将 MainActivity 管理的所有内容耦合到 Fragment 中,并且我希望使用已缓存的虚拟机实例。

但是,这行不通。我的工厂对象永远不会被实例化;相反,使用默认工厂,并抛出异常,因为它不知道如何实例化我的特定 ViewModel 类。

我发现虚拟机实际上从未在 MainActivity 中实例化,因为它目前还没有被它触及。

VM 的实例化似乎被推迟到 Fragment,正如我上面所说,Factory 不再可用。

我对这里发生的事情的理解正确吗?

我的结构是仅将工厂传递到 Activity 中的

by
语句中,仅使用裸露的
by
在片段中实例化(检索缓存),对吗?

我注意到,我可以通过在我的虚拟机上简单地设置一个虚拟函数来使其全部工作,该函数什么也不做,只是通过在

MyActivity
中的那个点强制实例化来使其“预热”。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //.. boilerplate from Wizard

        // Seems to work, only if I add this below, which does 
        //   nothing
        viewModel.setDummy(1)

    }
}

我看到的所有其他帖子都说

by
get
机制是可以互换的。

这是我的主要问题:

真的没有办法立即实例化虚拟机吗? 我应该使用虚拟预热方法作为永久解决方案吗?

这是我主要工作的帖子

android kotlin fragment viewmodel lazy-evaluation
1个回答
0
投票

by viewModels()
返回
Lazy
因此它只会在第一次使用时才会被初始化,在您的情况下是片段。您可以使用
MainActivity.onCreate()
手动初始化
ViewModelProvider
中的 ViewModel。

MainActivity.kt

private lateinit viewModel: AutomationViewModel

override fun onCreate(...) {
    super.onCreate(...)
    viewModel = ViewModelProvider(
        this,
        AutomationViewModelFactory(this.application, SettingsRepository(dataStore))
    )
© www.soinside.com 2019 - 2024. All rights reserved.