【问题标题】:StateFlow: Cancellation of Older Emitted State After CollectingStateFlow:收集后取消旧的发射状态
【发布时间】:2022-01-18 09:57:57
【问题描述】:

我在 kotlin 流程中相对较新,我正在使用 android 中的流程创建登录模块。过去几天,我在 ViewModels 中收集它时一直被困在流程中,但是当我使用错误的凭据请求其缓存所有状态时,我遇到了问题。输入正确的凭据后,用户导航到主 Activity,但正在使用每个发出的状态创建 MainActivity 的实例:示例(用户输入 3 个错误的凭据和 1 个正确的凭据:创建了 4 个 MainActivity 实例) .那么,有什么方法可以取消之前的发射并只显示最新的请求。我也在使用 collectLatest ,但它也不起作用。下面是代码。

登录活动

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(mViewBinding.root)

        loginListener()
        

    

    }
    override fun onStart() {
        super.onStart()
        initViews()
        handleNetworkChanges()
    }

    private fun observeLogin() {
        lifecycleScope.launchWhenCreated {
          mViewModel.loginCredentials.collect { state ->
              when(state){
                  is State.Loading -> {
                      showLoading()
                  }
                  is State.Success -> {
                      Timber.d("I m in Success" + state.data)
                      val intent = Intent(this@LoginActivity,MainActivity::class.java)
                      startActivity(intent)
                      closeLoading()
                      finish()

                  }
                  is State.Error -> {
                      val errorResponse = gson.fromJson(state.message,LoginResponse::class.java)
                      showToast(errorResponse.messages)
                      closeLoading()
                  }
              }
          }
        }
    }
private fun loginListener() {
        mViewBinding.neumorphButtonSignIn.setOnClickListener {
            observeLogin()
            phoneNumber = mViewBinding.edtPhoneNumber.text.toString()
            pin = mViewBinding.oldPIN.text.toString()

            if (phoneNumber.isValidPhone()) {
                sendLoginCredentials(phoneNumber ,pin)
            }
        else {


                mViewBinding.edtPhoneNumber.snack("Please Enter valid phone number") {
                    action("ok") {
                        dismiss()
                    }
                }


            }
        }
    }
    private fun sendLoginCredentials(phoneNumber: String , pin: String) = mViewModel.postLoginCredentials("03XXXX" , "1234")

登录视图模型

@ExperimentalCoroutinesApi
@HiltViewModel
class LoginViewModel @Inject constructor(
    private val loginRepository: LoginRepository,

) : ViewModel() {
    private val _loginCredentials: MutableStateFlow<State<LoginResponse>> = MutableStateFlow(State.Empty())
    val loginCredentials: StateFlow<State<LoginResponse>> get() = _loginCredentials

    fun postLoginCredentials(phoneNumber: String, pin: String) {
        Timber.d("postLoginCredentials: $phoneNumber + $pin")
        _loginCredentials.value = State.loading()
        viewModelScope.launch {
            loginRepository.login(LoginRequest(phoneNumber,pin))
                .map { response -> State.fromResource(response) }
                .collect{state -> _loginCredentials.value = state }
        }
    }

}

登录库

class LoginRepository @Inject constructor(
    private val apiInterface: APIInterface
) {

    fun login(loginRequest: LoginRequest): Flow<ResponseAPI<LoginResponse>> {
        return object : NetworkBoundRepository<LoginRequest, LoginResponse>() {

            override suspend fun fetchFromRemote(): Response<LoginResponse> = apiInterface.createLoginRequest(
               loginRequest
           )
        }.asFlow()
    }

NetworkBoundRepository

abstract class NetworkBoundRepository<RESULT, REQUEST> {

    fun asFlow() = flow<ResponseAPI<REQUEST>> {

        val apiResponse = fetchFromRemote()

        val remotePosts = apiResponse.body()

        if (apiResponse.isSuccessful && remotePosts != null) {
            emit(ResponseAPI.Success(remotePosts))
        } else {
            // Something went wrong! Emit Error state.
            emit(ResponseAPI.Failed(apiResponse.errorBody()!!.string()))
        }

        
    }.catch { e ->
        e.printStackTrace()
        emit(ResponseAPI.Failed("Network error! Can't get latest posts."))
    }


    @MainThread
    protected abstract suspend fun fetchFromRemote(): Response<REQUEST>
}

有什么方法可以创建 MainAcitivity 的一个实例而忽略较旧的发出响应?任何可以工作的操作员。非常感谢这方面的任何帮助。谢谢。

【问题讨论】:

    标签: android android-studio kotlin mvvm kotlin-stateflow


    【解决方案1】:

    实际上,当我将其移至onCreate() 时,我从登录单击侦听器中调用了observeLogin(),这在我的项目中造成了这种混乱。一切都按预期进行。所以,把这个发给不会坚持这个的新手。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-06
      • 1970-01-01
      • 2021-09-17
      • 1970-01-01
      • 2022-12-06
      • 1970-01-01
      • 2020-12-13
      相关资源
      最近更新 更多