{"id":15,"date":"2023-02-23T01:01:46","date_gmt":"2023-02-23T01:01:46","guid":{"rendered":"https:\/\/leopoldo.dev\/blog\/?p=15"},"modified":"2023-02-23T02:25:09","modified_gmt":"2023-02-23T02:25:09","slug":"from-mvvm-to-vip-understanding-android-architecture-patterns","status":"publish","type":"post","link":"https:\/\/leopoldo.dev\/blog\/2023\/02\/23\/from-mvvm-to-vip-understanding-android-architecture-patterns\/","title":{"rendered":"From MVVM to VIP: Understanding Android Architecture Patterns"},"content":{"rendered":"\n<figure class=\"wp-block-image\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"319\" src=\"https:\/\/leopoldo.dev\/blog\/wp-content\/uploads\/2023\/02\/Screen-Shot-2023-02-22-at-19.00.48-1024x319.png\" alt=\"\" class=\"wp-image-16\" srcset=\"https:\/\/leopoldo.dev\/blog\/wp-content\/uploads\/2023\/02\/Screen-Shot-2023-02-22-at-19.00.48-1024x319.png 1024w, https:\/\/leopoldo.dev\/blog\/wp-content\/uploads\/2023\/02\/Screen-Shot-2023-02-22-at-19.00.48-300x94.png 300w, https:\/\/leopoldo.dev\/blog\/wp-content\/uploads\/2023\/02\/Screen-Shot-2023-02-22-at-19.00.48-768x239.png 768w, https:\/\/leopoldo.dev\/blog\/wp-content\/uploads\/2023\/02\/Screen-Shot-2023-02-22-at-19.00.48-1200x374.png 1200w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>When it comes to developing mobile apps for Android, choosing the right architecture pattern is crucial for creating a scalable, maintainable, and easy-to-test app. There are several popular architecture patterns among developers, each with its own set of advantages and disadvantages. In this blog post, we&#8217;ll take a fun look at the differences between five of the most popular patterns: MVVM, MVP, MVI, VIP, and Redux.<\/p>\n\n\n\n<h2>MVVM (Model-View-ViewModel)<\/h2>\n\n\n\n<p>MVVM is a widely used architecture pattern in Android development. In this pattern, the model represents the data and business logic, the view is responsible for displaying the data, and the ViewModel acts as an intermediary between the view and the model. This pattern is known for its ability to facilitate testing and to separate concerns effectively.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">class UserViewModel : ViewModel() {\n    val userLiveData = MutableLiveData<User>()\n    fun getUser() {\n        \/\/ fetch user data from model and update LiveData\n        val user = userRepository.getUser()\n        userLiveData.postValue(user)\n    }\n    fun updateUserPicture(pictureUri: Uri) {\n        \/\/ update user's profile picture in model\n        userRepository.updateUserPicture(pictureUri)\n    }\n}<\/pre>\n\n\n\n<p>In this example, <code>UserViewModel<\/code> acts as an intermediary between the view and the model to display user data on the screen. The ViewModel contains an instance of <code>MutableLiveData<\/code> that is updated when <code>getUser()<\/code> is called, which in turn calls the model&#8217;s <code>getUser()<\/code> method to retrieve the user data. Additionally, the ViewModel also provides a method <code>updateUserPicture()<\/code> to update the user&#8217;s profile picture in the model.<br><\/p>\n\n\n\n<h2>MVP (Model-View-Presenter)<\/h2>\n\n\n\n<p>MVP is another popular architecture pattern that is widely used in Android development. In this pattern, the view is responsible for displaying the data, the model represents the data and business logic, and the presenter acts as an intermediary between the view and the model. This pattern is known for its ability to facilitate testing and to separate concerns effectively.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">class ToDoListPresenter(private val view: ToDoListView,\n                        private val model: ToDoListModel) {\n    \n    fun loadTasks() {\n        val tasks = model.getTasks()\n        view.showTasks(tasks)\n    }\n    \n    fun addTask(task: Task) {\n        model.addTask(task)\n        view.showTaskAdded()\n    }\n    \n    fun completeTask(task: Task) {\n        model.completeTask(task)\n        view.showTaskCompleted()\n    }\n}<\/pre>\n\n\n\n<p>In this example, <code>ToDoListPresenter<\/code> acts as an intermediary between the view and the model to manage tasks in a to-do list app. The Presenter contains references to both the view and the model, and provides methods <code>loadTasks()<\/code>, <code>addTask()<\/code>, and <code>completeTask()<\/code> to handle user input and update the view with the latest data.<\/p>\n\n\n\n<h2>MVI (Model-View-Intent)<\/h2>\n\n\n\n<p>MVI is a relatively new architecture pattern that is gaining popularity in Android development. In this pattern, the model represents the data and business logic, the view is responsible for displaying the data, and the intent is used to handle user actions. This pattern is known for its ability to handle complex user interactions and to reduce the number of bugs.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sealed class SearchIntent {\n    object LoadData : SearchIntent()\n    data class SearchQuery(val query: String) : SearchIntent()\n}\nclass SearchViewModel(private val searchUseCase: SearchUseCase) : ViewModel() {\n    private val _searchViewState = MutableLiveData<SearchViewState>()\n    val searchViewState: LiveData<SearchViewState> = _searchViewState\n    fun processIntents(intents: Flow<SearchIntent>) {\n        viewModelScope.launch {\n            intents.collect { intent ->\n                when (intent) {\n                    is SearchIntent.LoadData -> {\n                        val results = searchUseCase.getInitialData()\n                        _searchViewState.value = SearchViewState.LoadedData(results)\n                    }\n                    is SearchIntent.SearchQuery -> {\n                        val results = searchUseCase.search(intent.query)\n                        _searchViewState.value = SearchViewState.SearchResults(results)\n                    }\n                }\n            }\n        }\n    }\n}\n<\/pre>\n\n\n\n<p>In this example, <code>SearchViewModel<\/code> uses the MVI pattern to handle user intents in a search functionality. The ViewModel contains a sealed class <code>SearchIntent<\/code> to represent different user intents, and a method <code>processIntents()<\/code> to collect and process these intents. The method uses a <code>Flow<\/code> to collect the intents, and a <code>when<\/code> statement to handle each intent and update the view state accordingly.<\/p>\n\n\n\n<h2>VIP (View-Interactor-Presenter)<\/h2>\n\n\n\n<p>VIP is an architecture pattern that is similar to MVP. In this pattern, the view is responsible for displaying the data, the presenter acts as an intermediary between the view and the interactor, and the interactor represents the business logic. This pattern is known for its ability to facilitate testing and to reduce the complexity of the code.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">interface LoginView {\n    fun showLoginSuccess()\n    fun showLoginError()\n}\n\ninterface LoginInteractor {\n    fun login(username: String, password: String)\n}\n\nclass LoginPresenter(private val view: LoginView,\n                     private val interactor: LoginInteractor)\n{\nfun login(username: String, password: String) {\n    interactor.login(username, password)\n}\n\nfun onLoginSuccess() {\n    view.showLoginSuccess()\n}\n\nfun onLoginError() {\n    view.showLoginError()\n}\n\n}\n\nclass LoginInteractorImpl(private val userRepository: UserRepository) : LoginInteractor {\n\noverride fun login(username: String, password: String) {\n    val user = userRepository.getUser(username, password)\n    if (user != null) {\n        \/\/ login success\n        presenter.onLoginSuccess()\n    } else {\n        \/\/ login error\n        presenter.onLoginError()\n    }\n}\n}<\/pre>\n\n\n\n<p>In this example,<code> LoginPresenter<\/code> acts as an intermediary between the view and the interactor (business logic) to handle user input in a login screen. The Presenter contains references to both the view and the interactor, and provides methods `<code>login()<\/code>`, `<code>onLoginSuccess()<\/code>`, and `<code>onLoginError()<\/code>` to handle user input and update the view with the latest data. The interactor `<code>LoginInteractorImpl<\/code>` takes care of the business logic of logging in a user, and communicates with the Presenter to update the view accordingly. <br><\/p>\n\n\n\n<h2>Redux<\/h2>\n\n\n\n<p>Redux is a state management architecture pattern that is widely used in Android development. In this pattern, the state of the app is kept in a single store, and all changes to the state are made through actions. This pattern is known for its ability to handle complex state management and to facilitate testing.<\/p>\n\n\n\n<p>example in Part 2<\/p>\n\n\n\n<h2>MVC (Model-View-Controller)<\/h2>\n\n\n\n<p>MVC is an architecture pattern that has been widely used in Android development. In this pattern, the model represents the data and business logic, the view is responsible for displaying the data, and the controller acts as an intermediary between the view and the model. This pattern is known for its ability to facilitate testing and to separate concerns effectively.<\/p>\n\n\n\n<p>example in Part 2<\/p>\n\n\n\n<p>In conclusion, choosing the right architecture pattern is crucial for creating a scalable, maintainable, and easy-to-test Android app. The patterns we&#8217;ve discussed in this blog post offer different approaches to solving the same problem, and each has its own set of strengths and weaknesses. Whether you choose MVVM, MVP, MVI, VIP, Redux, or MVC, what&#8217;s important is that you choose an architecture pattern that works for your specific needs and helps you to create a great app.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When it comes to developing mobile apps for Android, choosing the right architecture pattern is crucial for creating a scalable, maintainable, and easy-to-test app. There are several popular architecture patterns among developers, each with its<\/p>\n","protected":false},"author":1,"featured_media":48,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[5,6],"tags":[4,3],"_links":{"self":[{"href":"https:\/\/leopoldo.dev\/blog\/wp-json\/wp\/v2\/posts\/15"}],"collection":[{"href":"https:\/\/leopoldo.dev\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/leopoldo.dev\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/leopoldo.dev\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/leopoldo.dev\/blog\/wp-json\/wp\/v2\/comments?post=15"}],"version-history":[{"count":5,"href":"https:\/\/leopoldo.dev\/blog\/wp-json\/wp\/v2\/posts\/15\/revisions"}],"predecessor-version":[{"id":22,"href":"https:\/\/leopoldo.dev\/blog\/wp-json\/wp\/v2\/posts\/15\/revisions\/22"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/leopoldo.dev\/blog\/wp-json\/wp\/v2\/media\/48"}],"wp:attachment":[{"href":"https:\/\/leopoldo.dev\/blog\/wp-json\/wp\/v2\/media?parent=15"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/leopoldo.dev\/blog\/wp-json\/wp\/v2\/categories?post=15"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/leopoldo.dev\/blog\/wp-json\/wp\/v2\/tags?post=15"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}