0

我有一个视图模型

@HiltViewModel
class LoginViewModel @Inject constructor(
    private val apiRepository: ApiRepository
) : ViewModel() {
    private val account = MutableLiveData<String>("123")

    private val password = MutableLiveData<String>("123")

    val message: MutableLiveData<String> = MutableLiveData()

    var loginResult: LiveData<Resource<UserInfo>> = MutableLiveData()

    fun signIn() {
        if (TextUtils.isEmpty(account.value)) {
            message.postValue("Please enter your account")
            return
        }

        if (TextUtils.isEmpty(password.value)) {
            message.postValue("please enter your password")
            return
        }

        // In this code, it doesn’t work. I think it’s because I didn’t observe it.  
        // Is there any better way to write it here?
        loginResult = apiRepository.signIn(account.value!!, password.value!!)
    }

    fun inputAccount(accountValue: String) {
        account.value = accountValue
    }

    fun inputPassword(passwordValue: String) {
        password.value = passwordValue
    }
}

这是我的界面

@AndroidEntryPoint
class LoginActivity : BaseActivity<ActivityLoginBinding>() {
    private val viewModel: LoginViewModel by viewModels()

    ......

    override fun initEvent() {
        binding.account.editText!!.addTextChangedListener { viewModel.inputAccount(it.toString()) }

        binding.password.editText!!.addTextChangedListener { viewModel.inputPassword(it.toString()) }

        binding.signIn.setOnClickListener {
            viewModel.signIn()
        }
    }

    override fun setupObservers() {
        viewModel.message.observe(this) {
            Snackbar.make(binding.root, it, Snackbar.LENGTH_SHORT).show()
        }

         /**
         * There will be no callback here, I know it’s because I’m observing
         * `var loginResult: LiveData<Resource<UserInfo>> = MutableLiveData()`
         * instead of `apiRepository.signIn(account.value!!, password.value!!)` 
         * because it was reassigned
         */
        viewModel.loginResult.observe(this) {
            Log.d("TAG", "setupObservers: $it")
        }
    }
}

所以我稍微调整了代码 LoginViewModel.signIn

fun signIn(): LiveData<Resource<UserInfo>>? {
    if (TextUtils.isEmpty(account.value)) {

        message.postValue("Please enter your account")
        return null
    }
    if (TextUtils.isEmpty(password.value)) {

        message.postValue("please enter your password")
        return null
    }

    return apiRepository.signIn(account.value!!, password.value!!)
}

LoginActivity.initEvent

override fun initEvent() {
    binding.signIn.setOnClickListener {
        viewModel.signIn()?.observe(this) {
            Log.d("TAG", "setupObservers: $it")
        }
    }
}

我查过LiveData的官方文档,livedata{}初始化的时候都是调用的。一直没有重新分配,但是如果登录了,就不能直接启动应用,请求网络。

协程文件

虽然我终于取得了我的成绩,但我认为这不是最好的做法,所以我想寻求帮助!</p>

  • 补充代码 ApiRepository
class ApiRepository @Inject constructor(
    private val apiService: ApiService
) : BaseRemoteDataSource() {
    fun signIn(account: String, password: String) =
        getResult { apiService.signIn(account, password) }
}

BaseRemoteDataSource

abstract class BaseRemoteDataSource {
    protected fun <T> getResult(call: suspend () -> Response<T>): LiveData<Resource<T>> =
        liveData(Dispatchers.IO) {
            try {
                val response = call.invoke()
                if (response.isSuccessful) {
                    val body = response.body()
                    if (body != null) emit(Resource.success(body))
                } else {
                    emit(Resource.error<T>(" ${response.code()} ${response.message()}"))
                }
            } catch (e: Exception) {
                emit(Resource.error<T>(e.message ?: e.toString()))
            }
        }
}
4

1 回答 1

0

或者我这样写

fun signIn() {
    if (TextUtils.isEmpty(account.value)) {
        message.postValue("Please enter your account")
        return
    }
    if (TextUtils.isEmpty(password.value)) {
        message.postValue("please enter your password")
        return
    }
    viewModelScope.launch {
        repository.signIn(account.value, password.value).onEach {
            loginResult.value = it
        }
    }
}

但我认为这并不完美

于 2021-08-09T14:24:25.700 回答