“The single responsibility principle states that every (…) class should have responsibility over a single part of the functionality provided by the software.” ( en.wikipedia.org/wiki/Single_responsibility_principle )
UI building in Android is usually delegated to one class (named Activity, Fragment, or View/Presenter). This usually entails the following tasks:
On top of that, Activity and Fragment are usually delegated extra responsibilities such as:
That’s not a single responsibility, and current ways of handling with such complexity includes inheritance or composition.
“Inheritance is when an object or class is based on another object (…) or class (…). It is a mechanism for code reuse and to allow independent extensions of the original software via public classes and interfaces. The relationships of objects or classes through inheritance give rise to a hierarchy.” ( en.wikipedia.org/wiki/Inheritance_(object-oriented_programming) )
For such complex structures, such as in UI building, inheritance can quickly become a hell. Check the following mock-case:
Code built along this inheritance tree quickly becomes unmanageable (“inheritance hell”). To circumvent that, developers often follow the principle of “Composition over inheritance”.
“Composition over inheritance (…) in object-oriented programming is the principle that classes should achieve polymorphic behavior and code reuse by their composition (by containing instances of other classes that implement the desired functionality).” ( en.wikipedia.org/wiki/Composition_over_inheritance )
The Composition Over Inheritance principle is a great idea and certainly can help us solve the issue presented above. There are, however, virtually no libraries, sample code, or tutorials available on how to implement this on Android. An easy way to start hacking around it is to use runtime parameters (a.k.a. intent extras) to make feature composition, but that still results in a huge unmanageable single class monstrosity.
Honorable mentions here are the LightCycle and CompositeAndroid libraries. Both are tightly tied to the Activity or Fragment, leaving other modern patterns such as MVP or MVVM out, are not very flexible as they rely solely on Android’s native callbacks (cannot add extra callbacks) and do not support inter-module communication.
Based on the presented issues developers face everyday, the EyeEm Android team started developing a pattern to solve in a more flexible way not directly attached to a component such as Activity or Fragment. The decoupling allows the pattern to be used for any class the developer wishes to make modular through composition.
The pattern is quite similar to the LightCycle/Composite approaches, and consists of 3 classes:
With that approach developers gain immediate advantages regarding
To make the implementation of the above pattern seamless for developers, a compile time code generation tool was created and we’ll see next how easy it is to break all those responsibilities previously presented (and more) into single responsibility classes.
To implement decorators first create a blueprint of the code that should be generated, here we’ll use an Activity with a RecyclerView as an example, but the same could be used in a Fragment, Presenter or even View. In this sample, we’ll use onCreate/onStart/onStop/onDestroy from the activity life-cycle, but also create a few extra callbacks that will suit the RecyclerView case.
This simple blueprint annotated with[email protected]
` will generate the complete implementation of the decorators pattern and a `Serializable` builder class that can be passed as parameter. To complete the Activity implementation we extend the generated class and bind the received builder to it.
Now the responsibilities can be easily distributed to bindable decorators. Every decorator contains all of the lifecycle callbacks and may implement any of the optional interfaces. And finally, composition can be obtained in a simple builder pattern:
Please check our Github for the library and a complete working sample app https://github.com/eyeem/decorator . The sample app morphs the Activity execution on each user tap by simply adding/removing decorators from the current activity before starting the next.
Most of the code shown above was hacked from that sample. There you’ll find a list of kind-of real implementation of decorators using Realm and Retrofit that loosely resembles the UI building tasks mentioned in the beginning of this article.
EyeEm already operates with decorators — and the experience has never been better. Check it out on the Play Store . We currently use Decorated view presenters (using Square Mortar library) for all the UI elements and Decorated activities for transitions, deal with different API levels, A/B testing, navigation, tracking, and a few special cases when onboarding new photographers.
The code and implementation shown above are only samples and intended purely as a guide.
While we built this for Android, the pattern is open to any use case. The library is a pure Java implementation that generates the code during compile time and can be used on any Java class, and we encourage developers to look to create modular single responsibility code in any of their Java projects!
Enough said- add it to your build.gradle and start building modular apps.