基于Kotlin实现的MVI,用最少的代码实现完整框架

概要

MVI(Model-View-Intent)框架是一种软件架构模式,尤其在移动应用开发中较为流行,它被设计来简化应用程序的复杂性和可维护性。MVI模式是对传统的MVVM(Model-View-ViewModel)模式的一种演进,强调了数据的单向流动和状态管理的重要性,这使得它在处理复杂的用户界面交互和状态变化时更加有效。

整体架构流程

技术名词解释

Model:
Model代表了应用程序的状态,通常是一个不可变的数据结构。
它可以包含业务逻辑或数据层的处理,但主要职责是存储和更新状态。
Model通常是响应Intent而产生新的状态。
View:
View负责展示Model中的数据,它是用户界面的表示。
View不直接与Model通信,而是通过Intent来表达用户的操作。
View通常会订阅Model的变化,并根据Model的状态更新UI。
Intent:
Intent是用户操作或者外部事件的抽象表示,比如按钮点击、网络请求完成等。
Intent触发Model的更新,从而导致View的重新渲染。
Intent可以看作是用户输入和系统输出之间的桥梁。

技术细节

帮助各位理解MVI

假设你正在玩一个电子游戏,游戏里有一个角色(可以把它想象成Model),一个屏幕(View),以及你的操作(Intent)。
Model(模型):这就像游戏里的角色,它包含了所有关于角色的信息,比如生命值、位置、装备等。每当游戏世界中发生一些事情,比如你打败了一个怪兽,Model就会更新,比如增加经验值或掉落物品。
View(视图):这是你看到的游戏画面,也就是屏幕上的显示。它不会自己决定要显示什么,而是根据Model里的信息来更新画面。比如,如果Model里的生命值减少了,View就会显示角色的生命条变短。
Intent(意图):这代表你的操作,比如按下的按键或触摸屏上的滑动。当你按下攻击键,这个动作就是Intent,它告诉游戏(Model)去做某些事情,比如让角色挥剑。

整体流程

1.封装BaseViewModel

open class BaseViewModel<I,S>(initState:S):ViewModel() {
	val intent  by lazy {
		Channel<I>(Channel.UNLIMITED)
	}
	val state  by lazy {
		MutableStateFlow<S>(initState)
	}
	val service:ApiService by lazy {
		service()
	}
}

2.封装BaseView

@Suppress("UNCHECKED_CAST")
abstract class BaseView<B:ViewDataBinding,VM:BaseViewModel<*,*>>:AppCompatActivity() {
	private val types by lazy {
		(javaClass.genericSuperclass as ParameterizedType).actualTypeArguments
	}
	val binding:B by lazy {
		val clazz = types[0] as Class<B>
		clazz.getMethod("inflate", LayoutInflater::class.java).invoke(null,layoutInflater) as B
	}
	val viewModel:VM by lazy {
		val clazz = types[1] as Class<VM>
		ViewModelProvider(this)[clazz]
	}
	
	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		setContentView(binding.root)
		initData()
		initView()
	}
	
	abstract fun initView()
	
	abstract fun initData()
}

3.封装完成,实际应用,获取意图

interface LoginIntent {
	data class login(val password:String,val username:String):LoginIntent
}

.4.获取状态

interface LoginState {
	data class LoginSuccess(val user:Res<LoginEntity>):LoginState
	data class LoginFail(val error:String):LoginState
	data object default:LoginState
}

5.实际运用之ViewModel

class LoginViewModel :BaseViewModel<LoginIntent,LoginState>(initState = LoginState.default) {
	init {
		viewModelScope.launch {
			intent.consumeAsFlow().collect{
				when(it){
					is LoginIntent.login->Login(it.password,it.username)
				}
			}
		}
	}
	
	
	
	private  fun Login(password: String, username: String) {
		viewModelScope.launch(Dispatchers.IO) {
			service.Login(password,username).collect{
				if(it.code == 0){
					state.value = LoginState.LoginSuccess(it)
				}else{
					state.value =(LoginState.LoginFail(it.msg))
				}
			}
		}
	}
}

这里的service是网络请求

6.实际应用之VIew

class LoginActivity : BaseView<ActivityLoginBinding, LoginViewModel>() {
	val map by lazy {
		mutableMapOf<String, String>()
	}
	
	override fun initView() {
		binding.user = map
		binding.btn.setOnClickListener {
			viewModel.intent.trySend(
				LoginIntent.login(
					map["password"] ?: "",
					map["username"] ?: ""
				)
			)
		}
	}
	
	override fun initData() {
		lifecycleScope.launch {
			viewModel.state.collect {
				when (it) {
					is LoginState.LoginSuccess -> {
						Toast.makeText(this@LoginActivity, "登录成功", Toast.LENGTH_SHORT).show()
						ARouter.getInstance().build("/login/main").navigation()
					}
					
					is LoginState.LoginFail -> {
						Toast.makeText(this@LoginActivity, "${it.error}", Toast.LENGTH_SHORT).show()
						Log.d("+++", "${it.error}")
					}
				}
			}
		}
		
	}
	
}

这里用的双向绑定

                                                           ~~~到此结束~~~

  • 14
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MVI是一种基于响应式编程的架构模式,它可以帮助我们更有效地管理应用程序的状态和响应用户交互。在Kotlin实现MVI框架需要以下步骤: 1. 定义状态类 首先,我们需要定义一个状态类,它将存储应用程序的状态。该类应该包含应用程序中所有可能的状态,例如:加载中、成功、错误等。 ```kotlin sealed class State { object Loading : State() data class Success(val data: List<String>) : State() data class Error(val message: String) : State() } ``` 2. 定义Action类 然后,我们需要定义一个Action类,它将存储用户操作的信息。该类应该包含应用程序中所有可能的操作,例如:加载数据、刷新数据等。 ```kotlin sealed class Action { object LoadData : Action() object RefreshData : Action() } ``` 3. 定义Reducer函数 Reducer函数是MVI模式的核心。Reducer函数将当前状态和Action作为参数,并返回新状态。在Reducer函数中,我们可以根据Action来进行状态的更新。 ```kotlin fun reduce(state: State, action: Action): State { return when (action) { is Action.LoadData -> State.Loading is Action.RefreshData -> state } } ``` 4. 定义View层 View层是用户界面的部分,它将显示应用程序的状态和响应用户操作。在View层中,我们需要订阅状态的变化,并根据状态来更新用户界面。 ```kotlin class MyActivity : AppCompatActivity() { private lateinit var viewModel: MyViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_my) viewModel = ViewModelProvider(this).get(MyViewModel::class.java) viewModel.state.observe(this, Observer { state -> when (state) { is State.Loading -> showLoading() is State.Success -> showData(state.data) is State.Error -> showError(state.message) } }) viewModel.dispatch(Action.LoadData) } private fun showLoading() { // 显示加载中的UI } private fun showData(data: List<String>) { // 显示数据的UI } private fun showError(message: String) { // 显示错误的UI } } ``` 5. 定义ViewModel层 ViewModel层是连接View层和Reducer函数的部分。在ViewModel层中,我们需要将Action传递给Reducer函数,并将新状态发送给View层。 ```kotlin class MyViewModel : ViewModel() { private val _state = MutableLiveData<State>() val state: LiveData<State> = _state fun dispatch(action: Action) { val newState = reduce(_state.value ?: State.Loading, action) _state.postValue(newState) } } ``` 这就是Kotlin实现MVI框架的基本步骤。当然,在实际应用中,我们可能需要更复杂的状态、Action和Reducer函数,但是这些步骤应该是通用的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值