android mvi架构_Android上的MVI体系结构入门

本文介绍了Android平台上的MVI(Model-View-Intent)架构,这是一种用于构建可维护和可测试应用程序的现代设计模式。内容包括MVI的背景、工作原理及如何在Android应用中实施。
摘要由CSDN通过智能技术生成

android mvi架构

介绍 (Introduction)

Like MVC, MVP or MVVM, MVI is an architectural design pattern that helps us better organize our code to create robust and maintainable applications. It is in the same family as Flux or Redux and was first introduced by André Medeiros. This acronym is formed by the contraction of the words Model, View and Intent.

与MVC,MVP或MVVM一样,MVI是一种体系结构设计模式,可帮助我们更好地组织代码以创建健壮且可维护的应用程序。 它与Flux或Redux属于同一家族,由AndréMedeiros首次引入。 该首字母缩略词是由“模型”,“视图”和“意图”这两个词的紧缩形成的。

We’ll try to describe the different elements of the MVI architecture so that you can understand their role within the architecture.

我们将尝试描述MVI体系结构的不同元素,以便您了解它们在体系结构中的作用。

Image for post
Figure 1
图1

意图 (Intent)

Represents the user’s intent when interacting with the UI. For example, a click on a button to refresh a list of data will be modeled as an Intent. To avoid any confusion with the Android framework Intent, we will call it in the rest of this article a UserIntent.

表示与UI交互时用户的意图。 例如,单击按钮以刷新数据列表将被建模为Intent。 为了避免与Android框架Intent混淆,在本文的其余部分中,我们将其称为UserIntent。

模型 (Model)

It is a ViewModel where different synchronous or asynchronous tasks are performed. It accepts UserIntents as input and produces one or more successive states as output. These states are exposed via a LiveData to be used by the view.

它是一个ViewModel,在其中执行不同的同步或异步任务。 它接受UserIntents作为输入,并产生一个或多个连续状态作为输出。 这些状态通过LiveData公开以供视图使用。

视图 (View)

The view simply processes immutable states that it receives from the ViewModel to update the UI. It also allows to transmit user actions to the ViewModel in order to accomplish defined tasks.

该视图仅处理从ViewModel接收的不可变状态以更新UI。 它还允许将用户操作传输到ViewModel,以完成定义的任务。

But it’s not finished, to set up an MVI archictecture, we need other elements like :

但这还没有完成,要建立MVI架构,我们需要其他元素,例如:

(State)

It represents an immutable state of sight. A new state is created by the ViewModel each time the view needs to be updated.

它代表着一成不变的视觉状态。 每次需要更新视图时,ViewModel都会创建一个新状态。

减速器 (Reducer)

When you want to create a new State, you use the Reducer. It is provided with the current state as well as new elements to be included and it takes care of producing an immutable state.

当您要创建新状态时,请使用Reducer。 它提供了当前状态以及要包含的新元素,并负责产生不可变状态。

MVI简而言之 (MVI in the nutshell)

As you can see on the Figure 1, all the actions that the user can perform on a view are translated as intention, in other words the user manifests the intention to do something by transmitting his intention to the model, the model receives the intention then performs the operation related to this intention, then the model returns a result in the form of a state, and the view will be able to update itself according to this state.

如您在图1上所看到的,用户可以在视图上执行的所有动作都被转换为意图 ,换句话说,用户通过将其意图传递给模型来表达意图做某事,然后模型接收意图执行与此意图相关的操作,然后模型以state的形式返回结果,并且视图将能够根据此state进行更新。

MVI was designed around the paradigm of reactive programming and uses observable flows to exchange messages between different entities. As a result, each of them will be independent and therefore more flexible and resilient. In addition, information will always flow in one direction: this concept is known as Unidirectional Data Flow or UDF. Once the architecture is established, the developer will find it easier to reason and debug if necessary. However, this concept must be strictly adhered to throughout the development process.

MVI是围绕React式编程范式设计的,并使用可观察的流程在不同实体之间交换消息。 结果,它们中的每一个将是独立的,因此更加灵活和有弹性。 此外,信息将始终沿一个方向流动:此概念称为单向数据流或UDF。 架构一旦建立,开发人员将发现在必要时可以更轻松地进行推理和调试。 但是,在整个开发过程中必须严格遵守这一概念。

MVI组件 (The MVI components)

To illustrate the MVI architecture, we’re going to develop step by step an application that retrieves the data online and then displays them in a recyclerView, the user will be able to refresh the list to get the new data, the application looks like that

为了说明MVI架构,我们将逐步开发一个应用程序,该应用程序将在线检索数据,然后将其显示在recyclerView中,用户将能够刷新列表以获取新数据,该应用程序看起来像这样

Image for post
Figure 2
图2

UI状态 (The UI state)

Extremely important thing with MVI, we model a complete state of the view with all the data necessary to display our UI

使用MVI极为重要的是,我们使用显示我们的UI所需的所有数据对视图的完整状态进行建模

And the state of figure 2 can be presented by this class

这个类可以表示图2的状态

data class UserState(
    val users: List<User> = listOf(),
    val isLoading: Boolean = false,
    val errorMessage: String? = null
) : IState

As you can see, the State class implements the IState interface, it’s just a matter of organization, and reusability you’ll see the advantage in the rest of the article.

如您所见,State类实现了IState接口,这只是组织问题,而可重用性将在本文的其余部分中体现出来。

interface IState { }

风景 (The View)

The View part is represented in our Android application by an Activity. It will implement a generic interface with a single render function that takes a State state as a parameter.

View部分在我们的Android应用程序中由一个Activity表示。 它将使用带有State状态作为参数的单个render函数实现通用接口。

interface IView<S: IState> {
    fun render(state: S)
}

用户意图 (The User Intent)

The UserIntent class represents the different actions the user can do on a particular view, and in our case the user may want to retrieve the data or refresh the view to get the new information,

UserIntent类表示用户可以对特定视图执行的不同操作,在我们这种情况下,用户可能希望检索数据或刷新视图以获取新信息,

We have used a Sealed class that models these “intentions” and allows us to deal with them exhaustively in the instruction when provided by Kotlin.

我们使用了Sealed类来对这些“意图”进行建模,并在Kotlin提供的说明中允许我们详尽地处理它们。

sealed class UserIntent : IIntent {
    object RefreshUsers : UserIntent()
    object FetchUsers : UserIntent()
}

The UserIntent class also implements an IIntent interface that we used to identify all the Intentions that the user can perform in our application.

UserIntent类还实现了一个IIntent接口,该接口用于标识用户可以在应用程序中执行的所有Intent。

interface IIntent {
  
}

该模型 (The model)

Let us now turn to the most interesting part of our logic. We will try to keep in mind the two concepts mentioned above: UDF and Reactive Programming. We will only use what Kotlin, LiveData and the Coroutines library offer.

现在让我们转向逻辑中最有趣的部分。 我们将尝试牢记上述两个概念:UDF和响应式编程。 我们将仅使用Kotlin,LiveData和Coroutines库提供的内容。

The ViewModel will implement a generic interface which exposes the state via a LiveData and which offers an entry point for UserIntents.

ViewModel将实现一个通用接口,该接口通过LiveData公开状态,并为UserIntents提供入口。

interface IModel<S: IState, I: IIntent> {
    val intents: Channel<I>
    val state: LiveData<S>
}

All the viewModels of our application will implement this interface and will receive the user’s intentions via a channel (for more information about the channel refer to the official Kotlin documentation).

我们应用程序的所有viewModels都将实现此接口,并将通过一个渠道接收用户的意图(有关该渠道的更多信息,请参阅Kotlin官方文档 )。

MVI实践 (MVI In Practice)

应用程序的ViewModel (The ViewModel of the application)

class UserViewModel(private val userApi: UserApi) : ViewModel(), IModel<UserState, UserIntent> {


    override val intents: Channel<UserIntent> = Channel(Channel.UNLIMITED)


    private val _state = MutableLiveData<UserState>().apply { value = UserState() }
    override val state: LiveData<UserState>
        get() = _state


    init {
        handlerIntent()
    }


    private fun handlerIntent() {
        viewModelScope.launch {
            intents.consumeAsFlow().collect { userIntent ->
                when(userIntent) {
                    UserIntent.RefreshUsers -> fetchData()
                    UserIntent.FetchUsers -> fetchData()
                }
            }
        }
    }


    private fun fetchData() {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                updateState { it.copy(isLoading = true) }
                updateState { it.copy(isLoading = false, users = userApi.getUser()) }
            } catch (e: Exception) {
                updateState { it.copy(isLoading = false, errorMessage = e.message) }
            }
        }
    }


    private suspend fun updateState(handler: suspend (intent: UserState) -> UserState) {
        _state.postValue(handler(state.value!!))
    }
}

The UserViewModel of our small application implements the generic IModel interface, and this ViewModel will be able to provide the view with a UserState state and will be able to handle UserIntent intentions, that’s why the type parameter looks like .

我们的小型应用程序的UserViewModel实现了通用的IModel接口,并且该ViewModel将能够为视图提供UserState状态,并且能够处理UserIntent意图,这就是type参数的样子。

IModel<UserState, UserIntent>

When implementing the IModel interface, the UserViewModel must implement both properties, the intents property that is initialized with UNLIMITED channel, and the state returns the value of a MutableViewModel that is initialized by the initial state of the view.

当实现IModel接口,所述UserViewModel必须实现这两种性质,即具有无限信道初始化的意图属性,并且状态返回一个值MutableViewModel由所述视图的初始状态初始化。

意向处理 (Intent handling)

fun handlerIntent() {
    viewModelScope.launch {
        intents.consumeAsFlow().collect { userIntent ->
            when(userIntent) {
                UserIntent.RefreshUsers -> fetchData()
                UserIntent.FetchUsers -> fetchData()
            }
        }
    }
}

The handlerIntentmethod collects the intentions that the user is going to send via the channel from the view and performs the appropriate processing according to the received intention.

handlerIntent方法从视图中收集用户要通过通道发送的意图,并根据接收到的意图执行适当的处​​理。

更新状态 (Update the state)

When you want to create a new State, you use the Reducer, It is provided with the current state as well as new elements to be included and it takes care of producing an immutable state.

当您想创建一个新的State ,可以使用Reducer ,它提供了当前状态以及要包含的新元素,并负责产生一个不变的状态。

This operation is performed by the updateState method, which takes as only parameter a lambda that takes the current state and returns another state.

此操作由updateState方法执行,该方法仅将一个lambda作为参数,该lambda获取当前状态并返回另一个状态。

private suspend fun updateState(handler: suspend (intent: UserState) -> UserState) {
    _state.postValue(handler(state.value!!))
}

主视图 (The Main View)

class MainActivity : AppCompatActivity(), IView<UserState> {


    private val mAdapter = ItemAdapter()
    private val mViewModel by viewModel<UserViewModel>()


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        recyclerView.adapter = mAdapter


        // Observing the state
        mViewModel.state.observe(this, Observer {
            render(it)
        })


        // Fetching data when the application launched
        lifecycleScope.launch {
            mViewModel.intents.send(UserIntent.FetchUsers)
        }


        // Refresh data
        btnRefresh.setOnClickListener {
            lifecycleScope.launch {
                mViewModel.intents.send(UserIntent.RefreshUsers)
            }
        }
    }


    override fun render(state: UserState) {
        with(state) {
            progressBar.isVisible = isLoading
            btnRefresh.isEnabled = !isLoading
            mAdapter.submitList(users)


            if (errorMessage != null) {
                Toast.makeText(this@MainActivity, errorMessage, Toast.LENGTH_SHORT).show()
            }
        }
    }
}

The View part is represented in our Android application by the MainActivity. It will implement a generic interface with a single render function that takes a State state as a parameter.

View部分在我们的Android应用程序中由MainActivity 。 它将使用带有State状态作为参数的单个render函数实现通用接口。

When the user click the refresh button, we send the RefreshUsers intent to the UserViewModel using the channel, this operation will update the state and the main activity will react to the state change by call the render method and pass to it new state that will be used to update the UI.

当用户单击刷新按钮,我们发送意图到了RefreshUsers UserViewModel使用信道,这个操作会更新状态和主要活动将通过电话的状态变化作出React的render方法,并传递给它新的状态,这将是用于更新UI。

结论 (Conclusion)

MVI is an architectural design pattern based on reactive programming.The goal is to have less complex code, testable and easy to maintain.An Intent (or UserIntent in this article) describes the action of a user.Actions are always executed following the same one-way circuit (UDF).We manipulate immutable states that model the view.A Reducer is a component that allows us to produce new states.

MVI是一种基于React式编程的体系结构设计模式,其目标是减少代码的复杂度,可测试性和易于维护性.Intent(或本文中的UserIntent)描述了用户的操作,操作始终在同一操作之后执行回路(UDF)。我们操纵为视图建模的不可变状态。Reducer是允许我们产生新状态的组件。

If you want to see the code more closely, the source code is available on the following link and If you have any kind of feedback, feel free to connect with me on Twitter.

如果您想更仔细地查看代码,可以在以下链接上找到源代码,如果有任何反馈,请随时在Twitter上与我联系。

翻译自: https://proandroiddev.com/getting-started-with-mvi-architecture-on-android-b2c280b7023

android mvi架构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值