Moviper


Source link: https://github.com/mkoslacz/Moviper

Moviper

A Mosby based VIPER library for Android

Why Moviper?

You got tired because of fact that your Activities and Fragments were becoming god classes, so you have migrated to MVP. Now you're tired of your god-class presenters and you just want to stop continuously wondering if you should pass a context to your presenters and make them platform-dependent and harder to mock and test, or maybe you should let your view-activity manage the system connected work. That's why you're here. My Android VIPER interpretation allows you keep your code clean, neat, and more SRP with minimal effort. You can find more info about benefits of using VIPER architecture in this article.

OK, but for every screen I have to create so many files!

To avoid manually creating all VIPER class files and managing their dependencies every time you want to create a new screen I created a generator that does all of necessary work for you. You can find it here.

Great! But I'm used to go with Mosby. What about all of its goodies?

Moviper has all of the Mosby's MVP Views mapped to fit VIPER requirements. Just simply replace Mvp with Viper and let the Android Studio do the autoimport for you.

For example MvpFragment maps to ViperFragment.

Dependency

Import the selected Moviper modules to your module gradle file. Moviper-rx 2.x.x is built on top of RxJava2. For RxJava1 legacy Moviper version 1.5.0 see below.

dependencies {

  // core modules, in the most common scenario importing one of these two will be enough
  compile 'com.mateuszkoslacz.moviper:moviper-rx:2.0.4' // RxJava communication based Moviper core (recommended)
  compile 'com.mateuszkoslacz.moviper:moviper-callbacks:2.0.4' // callbacks communication based Moviper core 

 // Mosby's viewstate Moviper views 
  compile 'com.mateuszkoslacz.moviper:moviper-viewstate:2.0.4'

 // Butterknife Moviper views
  compile 'com.mateuszkoslacz.moviper:moviper-butterknife:2.0.4'
  // Butterknife Moviper views with Mosby's viewstate
  compile 'com.mateuszkoslacz.moviper:moviper-butterknife-viewstate:2.0.4'

 // Databinding Moviper Views 
  compile 'com.mateuszkoslacz.moviper:moviper-databinding:2.0.4'
  // Databinding Moviper Views Mosby's viewstate
  compile 'com.mateuszkoslacz.moviper:moviper-databinding-viewstate:2.0.4'

 // Recyclerview Moviper extension, allows you create the Viper classes set for every RecyclerVew cell
  compile 'com.mateuszkoslacz.moviper:moviper-recyclerview:2.0.4'
  // Butterknife Moviper Recyclerview cells
  compile 'com.mateuszkoslacz.moviper:moviper-recyclerview-butterknife:2.0.4'
  // Databinding Moviper Recyclerview cells
  compile 'com.mateuszkoslacz.moviper:moviper-recyclerview-databinding:2.0.4'

 // Android Service Moviper extensions 
  compile 'com.mateuszkoslacz.moviper:moviper-service:2.0.4'

 // optional testing utils, still beta, it has to be debug-compiled and causes some minor Manifest issues on debug builds
  debugCompile 'com.mateuszkoslacz.moviper:moviper-test:2.0.4' 
}

RxJava1 legacy version:

dependencies {

  // legacy, RxJava1 based versions of Moviper modules. You can use them with combination of 2.x.x modules not mentioned here
  compile 'com.mateuszkoslacz.moviper:moviper-rx:1.5.0'

debugCompile 'com.mateuszkoslacz.moviper:moviper-test:1.5.0' 
}

If you are upgrading Moviper you should probably check out the Changelog and/or the Migration guide.

Getting started

I strongly recommend you starting with reading a step-by-step tutorial I included in this blog post.

Alternatively you can check out the samples. I recommend starting with sample-super-rx-ai for Java with RxJava and Moviper Showcase repo or sample-super-rx-ai-kotlin for Kotlin with RxJava to see the most powerful Moviper architecture classes.

After that, just create a VIPER files set in your project using Moviper Template Generator, fill up the contract, generate missing methods using Android Studio autofix and implement them. That's simple!

For more basic usage you shall check out:

Samples listing

Advanced features

Args Bundle

You can easily pass extras from your Activity or Fragment to the presenter using Moviper Args Bundle. You can check out how to use it in the Sample's FullscreenPhotoPresenter constructor and its call.

Moviper Inter-Presenter-Communication

Referenced as IPC. It's RxJava based, so it works only on the Rx-flavor of Moviper.

Sample usage available in sample-ipc

Quickstart

Enable IPC in your Application class onCreate() method.

Moviper.getInstance().setConfig(

new Config.Builder()

  .withPresenterAccessUtilEnabled(true) // plain IPC

  .withInstancePresentersEnabled(false) // acces to specific presenters

  .build());
Plain IPC

You can access all alive Presenters of a given class from any place in your app like this:

Moviper.getInstance().getPresenters(SomePresenter.class)

.subscribe(somePresenter -> somePresenter.someMethod(false));
 // stream of all Presenters goes here

For readability mark your external methods in the Presenter using the @ExternalCall annotation.

Instance Presenters Access

If you set the withInstancePresentersEnabled in the config to true you can use Instance Presenter Access. After that you must ensure that every Presenter of given class has an unique name. To do so you have to override Presenter String getName() method (in default it returns "default").

After that you can access any Presenter Instance like this:

Moviper.getInstance().getPresenterInstance(SomePresenter.class, "someName")

.subscribe(somePresenter -> somePresenter.someMethod(false));
 // exactly one or zero Presenters with given name and class goes here

VIPER ViewHolders

need importing moviper-recyclerview module

For complex RecyclerView list elements and/or multiple views on RecyclerViewlist you can design your app in the way that treats every list element as a separate VIPER View with its own contract. Generating such ViewHolders is supported in the Moviper Template Generator. For the sample usage check out the sample-recyclerview.

Autoinject Views

AutoInject (Ai) Views that allow you to skip overriding the onCreate(...) / onViewCreated(..) method. Instead, in plain Ai Views you have to provide the layout id by overriding a getLayoutId() method and to perform any view injections, getting references to views etc. by overriding a injectViews() method. In addition, it contains the pre-baked classes, where these methods are already implemented inside of base classes for:

  • Butterknife - moviper-butterknife module (check out sample-rx-ai),
  • DataBinding - moviper-databinding module (just like in sample-super-rx-databinding, but not using passive views),
  • for Kotlin Android Extensions you shall use regular Ai Views from base module (just like in sample-super-rx-ai-kotlin, but not using passive views).

Passive Views

Passive Views (based on AutoInject ones) that enforces developer to create passive views, that are not aware of existence of Presenter. All communication from View to Presenter has to be done through providing Observables with given UI events. It's enforced by the fact that getPresenter() method of this kind of views does not return Presenter of some exact type, but as a general ViperPresenter, so calling any meaningful methods on it is impossible. As in the previous point, it also contains the pre baked classes for:

  • Butterknife - moviper-butterknife module (just like in sample-super-rx-ai-kotlin, but using passive views),
  • DataBinding - moviper-databinding module (check out sample-super-rx-databinding),
  • for Kotlin Android Extensions you shall use regular AiPassive Views from base module (check out sample-super-rx-ai-kotlin).

Choosing Presenter on runtime

A MoviperPresentersDispatcher tool allows you to choose the View's (especially Activity) presenter on the runtime without a need of putting it to the Bundle with all it's limitations or switching in . Sample launching of Activity with given presenter is available in sample-super-rx-ai, in ListingRouting#startUserDetailsActivity(...) here, and adjusting Activity to be started with any presenter that fits the View interface is showcased in UserDetailsActivity#createPresenter() here.

Attaching multiple presenters to the View

ViperPresentersList allows you to easily attach multiple presenters to the Passive Views. Sample usage is very simple and available in sample-super-rx-ai in UserDetailsActivity#createPresenter() here.

Service based VIPERs

Allow you to maintain a uniform architecture between your app's views and services. It includes support for:

  • regular Service's
  • IntentService's

Sample usage is showcased in sample-service

Independent VIPERS

need importing moviper-service module

Allow you to maintain a uniform architecture between your app's views and complex task objects that aren't strictly connected with any specific Android component.

Sample usage available in sample-independent-viper.

Test utils

Optional moviper-test module (see Dependency) contains useful testing tools:

  • FragmentTestRule to perform Fragment instrumentation tests in isolation,
  • MoviperActivityTestRule to perform Viper Activity instrumentation tests with proper cleanup,
  • ViewHolderTestRule to perform Recyclerview's ViewHolder instrumentation tests in isolation,
  • RxAndroidSchedulersOverrideRule to override AndroidSchedulers.mainThread() behaviour in unit tests,
  • ViewHolderUnitTestAcrivity to perform Recyclerview's ViewHolder Robolectric unit tests in isolation,
  • RecyclerViewMatcher to match RecyclerView's contents in Espresso instrumentation tests.

Check out the test modules of the samples to check out how easy is testing with Moviper and to see various usecases of moviper-test module.

Credits

This library is built on top of a great Mosby library by Hannes Dorfmann. Check out the project website.

I've also used a Lucas Urbas Interactor implementation idea presented in his Search viper architecture example.

I have followed Publish AAR to jCenter and Maven Central by Lopez Mikhael to publish Moviper to jCenter.

The great thanks for the my team that helped me in Moviper development implementing my ideas under my guidance:

License

Copyright 2017 Mateusz Ko?lacz  Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License. You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 

Resources

Got idea from Android Clean Architecture, this is a very simple Android app which describes how we can design a clean and clear architecture for an Android App.

Dragueur can move any view with one finger.

Android library that let you easily set lock activity for you application.

View that shows quick actions when long pressed, inspired by Pinterest.

Widget that generates pulsation relative to your icons.

An Android library to cache any serializable objects to disk, using a LRU cache implementation, with the possibility to specify an expiry time for each entry and a maximum size that can be allocated.

Topics


2D Engines   3D Engines   9-Patch   Action Bars   Activities   ADB   Advertisements   Analytics   Animations   ANR   AOP   API   APK   APT   Architecture   Audio   Autocomplete   Background Processing   Backward Compatibility   Badges   Bar Codes   Benchmarking   Bitmaps   Bluetooth   Blur Effects   Bread Crumbs   BRMS   Browser Extensions   Build Systems   Bundles   Buttons   Caching   Camera   Canvas   Cards   Carousels   Changelog   Checkboxes   Cloud Storages   Color Analysis   Color Pickers   Colors   Comet/Push   Compass Sensors   Conferences   Content Providers   Continuous Integration   Crash Reports   Credit Cards   Credits   CSV   Curl/Flip   Data Binding   Data Generators   Data Structures   Database   Database Browsers   Date &   Debugging   Decompilers   Deep Links   Dependency Injections   Design   Design Patterns   Dex   Dialogs   Distributed Computing   Distribution Platforms   Download Managers   Drawables   Emoji   Emulators   EPUB   Equalizers &   Event Buses   Exception Handling   Face Recognition   Feedback &   File System   File/Directory   Fingerprint   Floating Action   Fonts   Forms   Fragments   FRP   FSM   Functional Programming   Gamepads   Games   Geocaching   Gestures   GIF   Glow Pad   Gradle Plugins   Graphics   Grid Views   Highlighting   HTML   HTTP Mocking   Icons   IDE   IDE Plugins   Image Croppers   Image Loaders   Image Pickers   Image Processing   Image Views   Instrumentation   Intents   Job Schedulers   JSON   Keyboard   Kotlin   Layouts   Library Demos   List View   List Views   Localization   Location   Lock Patterns   Logcat   Logging   Mails   Maps   Markdown   Mathematics   Maven Plugins   MBaaS   Media   Menus   Messaging   MIME   Mobile Web   Native Image   Navigation   NDK   Networking   NFC   NoSQL   Number Pickers   OAuth   Object Mocking   OCR Engines   OpenGL   ORM   Other Pickers   Parallax List   Parcelables   Particle Systems   Password Inputs   PDF   Permissions   Physics Engines   Platforms   Plugin Frameworks   Preferences   Progress Indicators   ProGuard   Properties   Protocol Buffer   Pull To   Purchases   Push/Pull   QR Codes   Quick Return   Radio Buttons   Range Bars   Ratings   Recycler Views   Resources   REST   Ripple Effects   RSS   Screenshots   Scripting   Scroll Views   SDK   Search Inputs   Security   Sensors   Services   Showcase Views   Signatures   Sliding Panels   Snackbars   SOAP   Social Networks   Spannable   Spinners   Splash Screens   SSH   Static Analysis   Status Bars   Styling   SVG   System   Tags   Task Managers   TDD &   Template Engines   Testing   Testing Tools   Text Formatting   Text Views   Text Watchers   Text-to   Toasts   Toolkits For   Tools   Tooltips   Trainings   TV   Twitter   Updaters   USB   User Stories   Utils   Validation   Video   View Adapters   View Pagers   Views   Watch Face   Wearable Data   Wearables   Weather   Web Tools   Web Views   WebRTC   WebSockets   Wheel Widgets   Wi-Fi   Widgets   Windows   Wizards   XML   XMPP   YAML   ZIP Codes