展示 jetpack compose中使用 mvvm mvi redux 各框架
增加maven仓库
maven { url "https://raw.githubusercontent.com/feiyin0719/compose_architecture/main" }
implementation 'com.iffly:redux:0.0.3'
创建state和action类,继承Reducer创建reducer类
data class CountAction(val type: CountActionType, val data: Int) {
enum class CountActionType {
Add, Reduce
}
companion object {
infix fun addWith(data: Int): CountAction {
return CountAction(CountActionType.Add, data = data)
}
infix fun reduceWith(data: Int): CountAction {
return CountAction(CountActionType.Reduce, data = data)
}
}
}
data class CountState(val count: Int = 1) {
val doubleCount: Int get() = count * 2
}
class CountReducer :
Reducer<CountState, CountAction>(CountState::class.java, CountAction::class.java) {
override fun reduce(
countState: CountState,
flow: Flow<CountAction>
): Flow<CountState> {
return flow.flowOn(Dispatchers.IO).flatMapConcat { action ->
flow {
if (action.type == CountAction.CountActionType.Add)
emit(countState.copy(count = countState.count + action.data))
else
emit(countState.copy(count = countState.count - action.data))
}
}.flowOn(Dispatchers.IO)
}
}
state和action使用data class 可以方便创建,同时可以基于koltin提供的copy方法快速更新state
state类需要提供无参初始化函数,以用于当作初始状态
reducer类 reduce方法传入当前state和action的流,可以方便的进行异步操作,最后返回state flow流即可
在app初始化时创建store,传入reducer list,这里实现js redux略有不同
val s =
storeViewModel(
listOf(CountReducer(), CountFloatReducer())
)
因为storeViewModel是绑定activity生命周期的,所以需要获取store时候只需要调用storeViewModel即可获取,然后通过getState获取需要的state即可,操作时候通过dispatch发送对应action即可
val s = storeViewModel()
val state: CountState by s.getState(CountState::class.java)
.observeAsState(CountState(1))
Content2(count = state.count) {
s.dispatch(CountAction reduceWith 1)
}
redux同时还提供中间件,可以更加丰富redux能力,middleware自定义也比较方便
比如我们实现一个redux-thunk,只需要继承Middleware
class FunctionActionMiddleWare : MiddleWare {
fun interface FunctionAction {
suspend operator fun invoke(dispatchAction: StoreDispatch, state: StoreState): Any?
}
override suspend fun invoke(store: StoreViewModel): (MiddleWareDispatch) -> MiddleWareDispatch {
return { next ->
MiddleWareDispatch { action ->
if (action is FunctionAction)
action(store, store)
else {
next.dispatchAction(action = action)
}
}
}
}
}
然后在创建store时候传入middleware即可
val s =
storeViewModel(
listOf(CountReducer(), CountFloatReducer()),
listOf(FunctionActionMiddleWare())
)
这样我们就可以dispatch一个 函数来作为action,以此来丰富dispatch能力,同时还可以返回值
val i = s.dispatch(FunctionActionMiddleWare.FunctionAction { storeDispatch: StoreDispatch, _: StoreState ->
storeDispatch.dispatch(CountAction addWith 1)
storeDispatch.dispatch(CountAction addWith 1)
1
})
我们开发中会存在这么一类状态,它是依赖于其他一个或者多个状态来变化的,我们提供了 depState方法来处理这种状态
我们只需要提前定义好依赖的状态和转换方法
data class DepState2(val depCount: Int = 0) {
companion object {
fun transform(countState: CountState, countFloatState: CountFloatState): DepState2 {
return DepState2((countState.count + (countFloatState.count)).toInt())
}
}
}
依赖的状态都是定义在transform的参数中,我们通过depState方法创建依赖状态
s.depState(DepState2::transform)
然后就可以普通状态一样通过getState方法获取使用
具体更多使用方法参考源码
redux基于jetpack的viewmodel livedata 以及kotlin协程 flow实现,即通过绑定activity的生命周期创建一个全局存在的store,store就是ViewModel,然后通过store保存状态和reducer,reducer处理过程是基于flow 进行处理,可以方便进行异步操作,state基于livedata来保存