{"id":4313,"date":"2017-03-28T19:20:07","date_gmt":"2017-03-28T19:20:07","guid":{"rendered":"https:\/\/www.ckl.io\/?p=4313"},"modified":"2022-07-01T17:42:42","modified_gmt":"2022-07-01T17:42:42","slug":"using-viper-architecture-android","status":"publish","type":"post","link":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/","title":{"rendered":"Using the VIPER architecture on Android"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">Starting as an Android developer and later working with iOS as well, I had contact with several different projects\u2019 architectures \u2013 some good and some bad.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I was happily using the MVP architecture for Android until I met \u2013 and worked eight months with \u2013 the VIPER architecture in an iOS project. When I came back to Android, I decided to adapt and implement VIPER on it, despite some other devs suggesting it wouldn\u2019t make sense to use an iOS architecture on Android. Given the fundamental difference between Android and iOS&#8217; frameworks, I had some questions about how useful would VIPER be for Android. Would it be doable and worth the effort? Let&#8217;s start with the basics.<\/span><\/p>\n<p><!--more--><\/p>\n<h2><span style=\"font-weight: 400;\">What is VIPER?<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">VIPER is a clean architecture mainly used in iOS app development. It helps keeping the code clean and organized, avoiding the <\/span><a href=\"http:\/\/khanlou.com\/2015\/12\/massive-view-controller\/\"><span style=\"font-weight: 400;\">Massive-View-Controller<\/span><\/a><span style=\"font-weight: 400;\"> situation.<\/span><\/p>\n<p><b>VIPER<\/b><span style=\"font-weight: 400;\"> stands for <\/span><b>V<\/b><span style=\"font-weight: 400;\">iew <\/span><b>I<\/b><span style=\"font-weight: 400;\">nteractor <\/span><b>P<\/b><span style=\"font-weight: 400;\">resenter <\/span><b>E<\/b><span style=\"font-weight: 400;\">ntity <\/span><b>R<\/b><span style=\"font-weight: 400;\">outer, which are classes that have a well defined responsibility, following the <\/span><a href=\"https:\/\/drive.google.com\/file\/d\/0ByOwmqah_nuGNHEtcU5OekdDMkk\/view\"><span style=\"font-weight: 400;\">Single Responsibility Principle<\/span><\/a><span style=\"font-weight: 400;\">. You can read more about it on <\/span><a href=\"https:\/\/www.ckl.io\/blog\/ios-project-architecture-using-viper\/\"><span style=\"font-weight: 400;\">this excellent article<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Android architectures<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">There are already some very good architectures for Android. The more famous being &nbsp;<a href=\"https:\/\/barta.me\/android-mvvm-pattern\/\" target=\"_blank\" rel=\"noopener noreferrer\">Model-View-ViewModel (MVVM)<\/a> and <a href=\"http:\/\/antonioleiva.com\/mvp-android\/\" target=\"_blank\" rel=\"noopener noreferrer\">Model-View-Presenter (MVP)<\/a>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">MVVM makes a lot of sense if you use it alongside data binding, and since I don&#8217;t like much the idea of data binding, I&#8217;ve always used MVP for the projects I&#8217;ve worked on. However, as projects grow, the presenter can become a huge class with a lot of methods, &nbsp;making it hard to maintain and understand. That happens because it is responsible for a lot of stuff: it has to handle UI Events, UI logic, business logic, networking and database queries. That violates the Single Responsibility Principle, something that VIPER can fix.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Let&#8217;s fix it!<\/span><\/h2>\n<p><img decoding=\"async\" class=\"wp-image-4329 aligncenter\" src=\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/giphy-11.gif\" alt=\"I CAN FIX IT!\" width=\"100%\"><\/p>\n<p><span style=\"font-weight: 400;\">With those problems in mind, I started a new Android project and decided to use MVP + Interactor (or VIPE, if you will). That allowed me to move some responsibility from the presenter to the Interactor. Leaving the presenter with UI events handling and preparing the data that comes from the Interactor to be displayed on the View. Then, the Interactor is only responsible for the business logic and fetching data from DBs or APIs.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Also, I started to use interfaces for linking the modules together. That way, they&nbsp;can&#8217;t access methods other than the ones declared on the interface. This protects the structure and helps defining a clear responsibility for each module, avoiding developer mistakes like putting the logic in the wrong place. Her<\/span>e&#8217;s how the interfaces look like<span style=\"font-weight: 400;\">:<\/span><\/p>\n<pre><code class=\"language-kotlin\">\nclass LoginContracts {\n  interface View {\n    fun goToHomeScreen(user: User)\n    fun showError(message: String)\n  }\n  \n  interface Presenter {\n    fun onDestroy()\n    fun onLoginButtonPressed(username: String, password: String)\n  }\n  \n  interface Interactor {\n    fun login(username: String, password: String)\n  }\n  \n  interface InteractorOutput {\n    fun onLoginSuccess(user: User)\n    fun onLoginError(message: String)\n  }\n}\n<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">And here&#8217;s&nbsp;some code to illustrate the classes that implement those interfaces&nbsp;(it&#8217;s in <\/span><a href=\"http:\/\/kotlinlang.org\/\" target=\"_blank\" rel=\"noopener noreferrer\"><span style=\"font-weight: 400;\">Kotlin<\/span><\/a><span style=\"font-weight: 400;\">, but Java should be the same).<\/span><\/p>\n<pre><code class=\"language-kotlin\">\nclass LoginActivity: BaseActivity, LoginContracts.View {\n  \n  var presenter: LoginContracts.Presenter? = LoginPresenter(this)\n\n  override fun onCreate() {\n    \/\/...\n    loginButton.setOnClickListener { onLoginButtonClicked() }\n  }\n  \n  override fun onDestroy() {\n    presenter?.onDestroy()\n    presenter = null\n    super.onDestroy()\n  }\n\n  private fun onLoginButtonClicked() {\n    presenter?.onLoginButtonClicked(usernameEditText.text, passwordEditText.text)\n  }\n  \n  fun goToHomeScreen(user: User) {\n    val intent = Intent(view, HomeActivity::class.java)\n    intent.putExtra(Constants.IntentExtras.USER, user)\n    startActivity(intent)\n  }\n  \n  fun showError(message: String) {\n    \/\/shows the error on a dialog\n  }\n}\n\nclass LoginPresenter(var view: LoginContracts.View?): LoginContracts.Presenter, LoginContracts.InteractorOutput {\n    var interactor: LoginContracts.Interactor? = LoginInteractor(this)\n\n    fun onDestroy() {\n      view = null\n      interactor = null\n    }\n\n    fun onLoginButtonPressed(username: String, password: String) {\n      interactor?.login(username, password)\n    }\n\n    fun onLoginSuccess(user: User) {\n      view?.goToNextScreen(user)\n    }\n    \n    fun onLoginError(message: String) {\n      view?.showError(message)\n    }\n}\n\nclass LoginInteractor(var output: LoginContracts.InteractorOutput?): LoginContracts.Interactor {\n  fun login(username: String, password: String) {\n    LoginApiManager.login(username, password)\n                ?.subscribeOn(Schedulers.io())\n                ?.observeOn(AndroidSchedulers.mainThread())\n                ?.subscribe({ \n                          \/\/does something with the user, like saving it or the token\n                          output?.onLoginSuccess(it)\n                          },\n                        { output?.onLoginError(it.message ?: \"Error!\") })\n  }\n}\n<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">The full code is available on <a href=\"https:\/\/gist.github.com\/marciogranzotto\/412c11947a311b65d75a8df5ad46b55d\" target=\"_blank\" rel=\"noopener noreferrer\">this Gist<\/a>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">You can see that the modules are created and linked together on startup. When the Activity is created, it initializes the Presenter, passing itself as the View on the constructor. The Presenter then initializes the Interactor passing itself as the <code>InteractorOutput<\/code><span style=\"font-weight: 400;\">. <\/span><\/span><\/p>\n<p><span style=\"font-weight: 400;\">On an iOS VIPER project this would be handled by the Router, creating the <code>UIViewController<\/code>, or getting it from a Storyboard, and then wiring all the modules together. But on Android we don&#8217;t create the <\/span><span style=\"font-weight: 400;\">Activities<\/span><span style=\"font-weight: 400;\"> ourselves: we have to use Intents, and we don&#8217;t have access to the newly created Activity from the previous one. This helps preventing memory leaks, but it can be a pain if you just want to pass data to the new module. We also can&#8217;t put the Presenter on the Intent\u2019s extras because it would need to be <code>Parcelable<\/code> or <code>Serializable<\/code>. Is just not doable.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">That&#8217;s why on this project I&#8217;ve omitted the Router. But is that the ideal case?<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">VIPE + Router<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">The above implementation of VIPE solved most of the MVP\u2019s problems, splitting the responsibilities of the Presenter with the Interactor.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">However, the View isn&#8217;t as passive as the iOS VIPER&#8217;s View. It has to handle all the regular View responsability plus routing to other modules. This should NOT be its responsibility and we can do better. Enter the Router.<\/span><\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-4330 size-full\" src=\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/giphy1.gif\" alt=\"The Router\" width=\"480\" height=\"270\"><\/p>\n<p>Here&#8217;s the differences between &#8220;VIPE&#8221; and VIPER:<\/p>\n<pre><code class=\"language-kotlin\">\nclass LoginContracts {\n  interface View {\n    fun showError(message: String)\n    \/\/fun goToHomeScreen(user: User)     \/\/This is no longer a part of the View's responsibilities\n  }\n\n  interface Router {\n    fun goToHomeScreen(user: User) \/\/ Now the router handles it\n  }\n}\n\nclass LoginPresenter(var view: LoginContracts.View?): LoginContracts.Presenter, LoginContracts.InteractorOutput {\n    \/\/now the presenter has a instance of the Router and passes the Activity to it on the constructor\n    var router: LoginContracts.Router? = LoginRouter(view as? Activity)\n    \n    \/\/...\n  \n    fun onLoginSuccess(user: User) {\n      router?.goToNextScreen(user)\n    }\n    \n    \/\/...\n}\n\nclass LoginRouter(var activity: Activity?): LoginContracts.Router {\n  fun goToHomeScreen(user: User) {\n    val intent = Intent(view, HomeActivity::class.java)\n    intent.putExtra(Constants.IntentExtras.USER, user)\n    activity?.startActivity(intent)\n  }\n}\n<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">Full code available <a href=\"https:\/\/gist.github.com\/marciogranzotto\/1c96e87484a17bd914e159b2604e6469\" target=\"_blank\" rel=\"noopener noreferrer\">here<\/a>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now we moved the view routing logic to the Router. It only needs an instance of the Activity so it can call the <\/span><code>startActivity<\/code><span style=\"font-weight: 400;\"> method. It still doesn&#8217;t wire everything together as the iOS VIPER, but at least it respects the Single Responsibility Principle.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Conclusion<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Having developed a project with MVP + Interactor and by helping a coworker to develop a full VIPER Android project, I can safely say that the architecture does work on Android and it&#8217;s worth it. The classes become smaller and more maintainable. It also guides the development process, because the architecture makes it clear where the code should be written.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Here on Cheesecake Labs we are planning to use VIPER on most of the new projects, so we can have better maintainability and clearer code. Also, it makes easier to jump from an iOS project to an Android project and vice-versa. Of course this is an evolving adaptation, so nothing here is carved in stone. We gladly appreciate some feedback about it!<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Starting as an Android developer and later working with iOS as well, I had contact with several different projects\u2019 architectures \u2013 some good and some bad. I was happily using the MVP architecture for Android until I met \u2013 and worked eight months with \u2013 the VIPER architecture in an iOS project. When I came [&hellip;]<\/p>\n","protected":false},"author":65,"featured_media":4336,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[432,7],"tags":[305,21,15],"class_list":["post-4313","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engineering","category-opinion","tag-tag-development","tag-tag-ios","tag-tag-mobile"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Using the VIPER architecture on Android<\/title>\n<meta name=\"description\" content=\"By helping a coworker to develop a full VIPER Android project, I can safely say that the architecture does work on Android and it&#039;s worth it.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using the VIPER architecture on Android\" \/>\n<meta property=\"og:description\" content=\"By helping a coworker to develop a full VIPER Android project, I can safely say that the architecture does work on Android and it&#039;s worth it.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/\" \/>\n<meta property=\"og:site_name\" content=\"Cheesecake Labs\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/cheesecakelabs\" \/>\n<meta property=\"article:published_time\" content=\"2017-03-28T19:20:07+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-07-01T17:42:42+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/Banner_androidviper2.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"720\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Cheesecake Labs\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@cheesecakelabs\" \/>\n<meta name=\"twitter:site\" content=\"@cheesecakelabs\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/\"},\"author\":{\"name\":\"Marcio Granzotto Rodrigues\"},\"headline\":\"Using the VIPER architecture on Android\",\"datePublished\":\"2017-03-28T19:20:07+00:00\",\"dateModified\":\"2022-07-01T17:42:42+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/\"},\"wordCount\":874,\"commentCount\":0,\"image\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/Banner_androidviper2.png\",\"keywords\":[\"development\",\"iOS\",\"Mobile\"],\"articleSection\":[\"Engineering\",\"Opinion\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/\",\"url\":\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/\",\"name\":\"Using the VIPER architecture on Android\",\"isPartOf\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/Banner_androidviper2.png\",\"datePublished\":\"2017-03-28T19:20:07+00:00\",\"dateModified\":\"2022-07-01T17:42:42+00:00\",\"author\":{\"@type\":\"person\",\"name\":\"Marcio Granzotto Rodrigues\"},\"description\":\"By helping a coworker to develop a full VIPER Android project, I can safely say that the architecture does work on Android and it's worth it.\",\"breadcrumb\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#primaryimage\",\"url\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/Banner_androidviper2.png\",\"contentUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/Banner_androidviper2.png\",\"width\":2000,\"height\":720,\"caption\":\"The Android droid and a friendly snake.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cheesecakelabs.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using the VIPER architecture on Android\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#website\",\"url\":\"https:\/\/cheesecakelabs.com\/blog\/\",\"name\":\"Cheesecake Labs\",\"description\":\"Nearshore outsourcing company for Web and Mobile design and engineering services, and staff augmentation for startups and enterprises..\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cheesecakelabs.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"name\":\"Marcio Granzotto Rodrigues\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2016\/11\/marcio3-300x300.jpg\",\"contentUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2016\/11\/marcio3-300x300.jpg\",\"caption\":\"Marcio Granzotto Rodrigues\"},\"description\":\"10 years of experience in Marketing and Sales in the Technology sector. My main purpose is help, support and structure efficient operations and also develop independent and multidisciplinary teams.\",\"url\":\"https:\/\/cheesecakelabs.com\/blog\/autor\/marcio\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Using the VIPER architecture on Android","description":"By helping a coworker to develop a full VIPER Android project, I can safely say that the architecture does work on Android and it's worth it.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/","og_locale":"en_US","og_type":"article","og_title":"Using the VIPER architecture on Android","og_description":"By helping a coworker to develop a full VIPER Android project, I can safely say that the architecture does work on Android and it's worth it.","og_url":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/","og_site_name":"Cheesecake Labs","article_publisher":"https:\/\/www.facebook.com\/cheesecakelabs","article_published_time":"2017-03-28T19:20:07+00:00","article_modified_time":"2022-07-01T17:42:42+00:00","og_image":[{"width":2000,"height":720,"url":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/Banner_androidviper2.png","type":"image\/png"}],"author":"Cheesecake Labs","twitter_card":"summary_large_image","twitter_creator":"@cheesecakelabs","twitter_site":"@cheesecakelabs","twitter_misc":{"Written by":null,"Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#article","isPartOf":{"@id":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/"},"author":{"name":"Marcio Granzotto Rodrigues"},"headline":"Using the VIPER architecture on Android","datePublished":"2017-03-28T19:20:07+00:00","dateModified":"2022-07-01T17:42:42+00:00","mainEntityOfPage":{"@id":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/"},"wordCount":874,"commentCount":0,"image":{"@id":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#primaryimage"},"thumbnailUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/Banner_androidviper2.png","keywords":["development","iOS","Mobile"],"articleSection":["Engineering","Opinion"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/","url":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/","name":"Using the VIPER architecture on Android","isPartOf":{"@id":"https:\/\/cheesecakelabs.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#primaryimage"},"image":{"@id":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#primaryimage"},"thumbnailUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/Banner_androidviper2.png","datePublished":"2017-03-28T19:20:07+00:00","dateModified":"2022-07-01T17:42:42+00:00","author":{"@type":"person","name":"Marcio Granzotto Rodrigues"},"description":"By helping a coworker to develop a full VIPER Android project, I can safely say that the architecture does work on Android and it's worth it.","breadcrumb":{"@id":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#primaryimage","url":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/Banner_androidviper2.png","contentUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2017\/03\/Banner_androidviper2.png","width":2000,"height":720,"caption":"The Android droid and a friendly snake."},{"@type":"BreadcrumbList","@id":"https:\/\/cheesecakelabs.com\/blog\/using-viper-architecture-android\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cheesecakelabs.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Using the VIPER architecture on Android"}]},{"@type":"WebSite","@id":"https:\/\/cheesecakelabs.com\/blog\/#website","url":"https:\/\/cheesecakelabs.com\/blog\/","name":"Cheesecake Labs","description":"Nearshore outsourcing company for Web and Mobile design and engineering services, and staff augmentation for startups and enterprises..","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cheesecakelabs.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","name":"Marcio Granzotto Rodrigues","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cheesecakelabs.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2016\/11\/marcio3-300x300.jpg","contentUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2016\/11\/marcio3-300x300.jpg","caption":"Marcio Granzotto Rodrigues"},"description":"10 years of experience in Marketing and Sales in the Technology sector. My main purpose is help, support and structure efficient operations and also develop independent and multidisciplinary teams.","url":"https:\/\/cheesecakelabs.com\/blog\/autor\/marcio\/"}]}},"_links":{"self":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts\/4313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/users\/65"}],"replies":[{"embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/comments?post=4313"}],"version-history":[{"count":1,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts\/4313\/revisions"}],"predecessor-version":[{"id":10304,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts\/4313\/revisions\/10304"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/media\/4336"}],"wp:attachment":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/media?parent=4313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/categories?post=4313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/tags?post=4313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}