ViewModel在相同活动中跨越片段的作用域

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

我有一个问题,我认为可以追溯到ViewModel范围界定。我在同一活动下的同一导航图中有两个片段。第一个片段LoginFragment实例化UserDataViewModel并将其某些数据填充到名为UserData]的对象中

第二个片段,TodayFragment应该使用UserDataViewModel,并使用已经填充的属性来做进一步的工作。但是,在TodayFragment尝试访问UserData对象时,该对象为空。要强调的是,UserDataViewModel仍然具有相同的内存地址,但是问题在于它丢失了对其数据值的引用。

我已对此进行了简化,以便数据仅从SharedPreferences中提取一个字符串并使用GSON对其进行解析。

LoginFragment

private lateinit var userDataViewModel: UserDataViewModel

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    MyApplication.appComponent?.inject(this)
    prefs = PreferenceManager.getDefaultSharedPreferences(context)

    userDataViewModel = activity?.run {
        ViewModelProviders
            .of(this, UserDataViewModelFactory(prefs, dataFetcherService))
            .get(UserDataViewModel::class.java)
    } ?: throw Exception("Invalid Activity")

    userDataViewModel.getUserData()
}

TodayFragment

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    prefs = PreferenceManager.getDefaultSharedPreferences(activity)

    userDataViewModel = activity?.run {
        ViewModelProviders
            .of(this, UserDataViewModelFactory(prefs, dataFetcherService))
            .get(UserDataViewModel::class.java)
    } ?: throw Exception("Invalid Activity")
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    userDataViewModel
        .getUserData()
        .observe(this, Observer {
            clubId = it.club_id  // <-- this is where it crashes since 'it' is null
        })
}

UserDataViewModel.kt

class UserDataViewModel(
    prefs: SharedPreferences,
    dataFetcherService: DataFetcherService)
    : ViewModel() {

    private val useCase = UserDataUseCase(prefs, dataFetcherService)

    val userData: MutableLiveData<UserData> by lazy {
        MutableLiveData<UserData>().apply { loadUserData() }
    }

    fun getUserData(): LiveData<UserData> {
        return userData
    }

    private fun loadUserData() {
        viewModelScope.launch {
            withContext(Dispatchers.IO) {
                try {
                    return@withContext useCase.loadUserData(USER_UNKNOWN)
                } catch (t: Throwable) {
                    return@withContext null
                }
            }
                ?.let {
                    userData.postValue(it)
                }
        }
    }
}

很奇怪的地方是视图模型的getUserData()方法中。当我在这些行上设置断点时:

return userDataMutableLiveData<UserData>().apply { loadUserData() }return@withContext useCase.loadUserData(USER_UNKNOWN)

这些断点都击中LoginFragment。但是,当它进入TodayFragment时,它会在视图模型中命中return userData,然后立即跳回到TodayFragment内部的观察者,并且视图模型内部的值具有空指针异常。

我认为在实例化视图模型本身的范围内是有意义的,但是为什么inside

值却为null?

出于调试目的,我正在对用例和存储库中的响应进行硬编码,以确保在视图模型中填充了一个值。

LoginFragment的屏幕截图

enter image description here

TodayFragment的屏幕截图(扩展了AbstractWorkoutFragment)

请注意mData现在如何为空,但ViewModel相同。enter image description here

我有一个问题,我认为可以追溯到ViewModel范围。我在同一活动下的同一导航图中有两个片段。第一个片段LoginLogin实例化了一个...

android mvvm android-livedata
1个回答
-1
投票

在包含两个片段的活动中实例化userDataViewModel。在活动中填充用户数据,并将其传递给子片段。

© www.soinside.com 2019 - 2024. All rights reserved.