LiveData 值 returns 空

LiveData value returns null

当我想在 viewModelScope 之外接收它时,为什么我的外部不可变 LiveData 值 returns 为空?

正如你在logcat中看到的,当我想在viewModelScope中接收它或第二次调用登录功能时没有问题。

Here is my view model

class LoginViewModel(private val mainRepository: MainRepository) : ViewModel() {

    private val _loginResponse = MutableLiveData<LoginResponse>()

    val loginResponse: LiveData<LoginResponse> = _loginResponse

    fun login(post: LoginBody) {
        viewModelScope.launch {
            try {
                _loginResponse.value = mainRepository.loginPost(post = post)
                Log.d(
                    LOGCAT,
                    "Login response : ${loginResponse.value?.data?.answerCount}"
                )
            } catch (e: Exception) {
                Log.d(LOGCAT, "Login error: $e")
            }
        }
        loginResponseOutsideOfTheViewModelScope()
    }

    fun loginResponseOutsideOfTheViewModelScope() {
        Log.d(LOGCAT, "LoginResponseOutsideOfTheViewModelScope : ${loginResponse.value?.data?.answerCount}")
    }
}

class LoginViewModelFactory(val app: GameApplication) :
    ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        val retrofitService = app.retrofit
        val context = app.applicationContext
        val mainRepository = MainRepository(
            retrofitService = retrofitService,
            context = context
        )
        val viewModel = LoginViewModel(mainRepository)
        return viewModel as T
    }
}

Here is my Fragment where I call login function.

class FirstFragment : Fragment() {

private var _binding: FragmentFirstBinding? = null

private val binding
    get() = _binding!!

private val viewModel: LoginViewModel by activityViewModels {
    LoginViewModelFactory(
        (activity?.application as GameApplication)
    )
}

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    _binding = FragmentFirstBinding.inflate(inflater)

    binding.lifecycleOwner = this

    binding.firstFragment = this

    return binding.root
}

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


    val myPost = LoginBody(
        deviceId = Settings.Secure.getString(
            requireContext().contentResolver, Settings.Secure.ANDROID_ID
        ),
        country = Locale.getDefault().country,
        language = Locale.getDefault().language,
        platform = Build.VERSION.SDK_INT.toString(),
        version = BuildConfig.VERSION_NAME,
        deviceModel = Build.MODEL
    )
    viewModel.login(myPost)
    }
}

Logcat

2021-10-21 16:32:10.676 1520-1520/com.example.a4p1w D/DEBUG: LoginResponseOutsideOfTheViewModelScope : null
2021-10-21 16:32:12.354 1520-1520/com.example.a4p1w D/DEBUG: Login response : 12

login 函数中你 launch 一个异步协同程序(它获取一个值并在记录它之前将其设置在 LiveData 上),然后你记录 LiveData 的当前值.该协程需要时间,因此“当前值”日志语句首先运行(这就是它们按该顺序打印的原因)。

您的 LiveData 最初没有值(您没有将值传递给构造函数):

private val _loginResponse = MutableLiveData<LoginResponse>()

so loginResponse.value returns null,直到你在它上面设置一个值(就像在你的协程中一样)。这就是为什么在协程完成时以及之后每次阅读它时它都能正常工作的原因