StateFlow:收集后取消旧的发射状态
Posted
技术标签:
【中文标题】StateFlow:收集后取消旧的发射状态【英文标题】:StateFlow: Cancellation of Older Emitted State After Collecting 【发布时间】: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)
.collectstate -> _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 的一个实例而忽略较旧的发出响应?任何可以工作的操作员。非常感谢这方面的任何帮助。谢谢。
【问题讨论】:
【参考方案1】:实际上,当我将其移至onCreate()
时,我从登录单击侦听器中调用了observeLogin()
,这在我的项目中造成了这种混乱。一切都按预期进行。所以,把这个发给不会坚持这个的新手。
【讨论】:
以上是关于StateFlow:收集后取消旧的发射状态的主要内容,如果未能解决你的问题,请参考以下文章
ViewModel中的StateFlow和SharedFlow,使用建议以及单元测试
ViewModel中的StateFlow和SharedFlow,使用建议以及单元测试