使用Kotlin在Android中使用事件总线图案
#kotlin #android #mobile #tristan

目录

  1. Event bus patter
  2. SharedFlow
  3. Extending the event bus pattern

代码

简介

  • 最近,我必须处理登录系统的一些相对复杂的状态逻辑,这就是我处理它的方式。

活动巴士模式

  • 因此,在书呆子谈话中,我们可以将事件总线模式描述为thisEvent-driven architecture pattern is a distributed asynchronous architecture pattern to create highly scalable reactive applications. The pattern suits for every level application stack from small to complex ones. The main idea is delivering and processing events asynchronously.

  • 基本上意味着我们可以拥有一个事件生产者对象和事件订户对象,这些对象等待并聆听事件生产者生成事件。然后,订户可以消费并回应这些事件。经典的心理模型下面是:

Event bus pattern

共享流

  • 现在,如果您不熟悉共享流量是什么,请知道这是hot flow。这意味着,当称为终端操作员collect{}时,它将始终处于活动状态。
  • 但是,我们将使用一个名为StateFlow的共享流的专门版本作为我们的活动总线:
class DataStoreViewModel(): ViewModel() {
private val _oAuthUserToken:MutableStateFlow<String?> = MutableStateFlow(null)

init{
  viewModelScope.launch{
     _oAuthUserToken.collect{ token ->
        token?.let{oAuthToken ->
     // make request now that the oAuthToken is not null
    }
}
  }
}

fun setOAuthToken(token:String){
   _oAuthUserToken.tryEmit(token)

}
}

  • 在上面的代码块中,我们是registering a subscriber,呼叫_oAuthUserToken.collect{}。这意味着只要其称为活动的范围,它将始终处于活动状态。如果viewModelScope被销毁,那么订户也是如此。

扩展活动巴士模式

  • 现在有时您的身份验证过程有多个步骤,并且每个步骤都取决于上一个步骤。同样,在任何时候,其中一个步骤可能会失败,这意味着依赖于该步骤的步骤也失败了。那么我们如何建模这个问题?我们像这样扩展了事件总线模式:
data class MainBusState(
    val oAuthToken:String? = null,
    val authUser:ValidatedUser? = null,
)

private val authenticatedUserFlow = combine(
        flow =MutableStateFlow<String?>(null),
        flow2 =MutableStateFlow<ValidatedUser?>(null)
    ){
        oAuthToken,validatedUser ->
        MainBusState(oAuthToken,validatedUser)

    }.stateIn(viewModelScope, SharingStarted.Lazily,
        MainBusState(oAuthToken = null, authUser = null)
    )
private val mutableAuthenticatedUserFlow = MutableStateFlow(authenticatedUserFlow.value)



private fun collectAuthenticatedUserFlow() =viewModelScope.launch {
        mutableAuthenticatedUserFlow.collect{mainState ->
            mainState.oAuthToken?.let{notNullToken ->
                validateOAuthToken(notNullToken)
            }
            mainState.authUser?.let {user ->
                _uiState.value = _uiState.value.copy(
                    clientId = user.clientId,
                    userId = user.userId
                )
            }
        }
    }

  • 上述代码可以分为4个步骤:

    1)模型您的主要状态
    2)将您的流量结合
    3)注册订户
    4)发出流量

1)模型您的主要状态

data class MainBusState(
    val oAuthToken:String? = null,
    val authUser:ValidatedUser? = null,
)

  • MainBusState中的每个值代表身份验证过程的一步。使用代码,您可以说我的应用需要一个OAuth身份验证令牌,并且需要验证用户。如果没有OAuth身份验证令牌,则无法实现经过验证的用户步骤

2)结合您的流量

private val authenticatedUserFlow = combine(
        flow =MutableStateFlow<String?>(null),
        flow2 =MutableStateFlow<ValidatedUser?>(null)
    ){
        oAuthToken,validatedUser ->
        MainBusState(oAuthToken,validatedUser)

    }.stateIn(viewModelScope, SharingStarted.Lazily,
        MainBusState(oAuthToken = null, authUser = null)
    )

  • 这样做是这样,我们可以将多个流动并将它们组合成一个对象。这使它变得更加容易,更可读,我们只需订阅单个流程即可。 stateIn()只是我们将combine()产生的冷流变成热流

3)注册订户

private fun collectAuthenticatedUserFlow() =viewModelScope.launch {
        mutableAuthenticatedUserFlow.collect{mainState ->
            mainState.oAuthToken?.let{notNullToken ->
                validateOAuthToken(notNullToken)
            }
            mainState.authUser?.let {user ->
                _uiState.value = _uiState.value.copy(
                    clientId = user.clientId,
                    userId = user.userId
                }
            }
        }
    }

  • 运行此功能时,它将持续到viewModelScope和IT注册2个订户。一个订户正在听oauthtoken,另一个订户向授权人聆听。两者都有各自的功能在不为空时运行。

4)发出流量

 mutableAuthenticatedUserFlow.tryEmit(
                    mutableAuthenticatedUserFlow.value.copy(
                        oAuthToken = newTokenStrin
                    )
                )

  • 然后,要将其值更新为我们的mutableBableAthenticatiCateDuserflow,我们简单地调用MainBusState的更新值。新的发射值将给出我们的mutableBealEterenticatiCatedUserFlow,并且更新的值将给他们各自的听众。

结论

  • 感谢您抽出宝贵的时间阅读我的博客文章。如果您有任何疑问或疑虑,请在下面发表评论或在Twitter上与我联系。