Google announced some awesome tools during #io17. They’re called Architecture Components, I’m going to assume you already know the basics about each, if not you can find videos and official documentation at the end of this article.
After studying these new elements I was able to write up a simple demo project, where you can check (especially if you don’t have any prior experience) how awesome reactive programming can be. For that reason and regarding my previous MVP project, I decided to open source the code and write a blog post about my experience.
MVVM + Observables + Repositories + Architecture Components 😨?
Don’t be overwhelmed, it’s simpler than it first looks, this is my interpretation:
TL;DR: Data source → Repository → ViewModel → View. There’s a nice diagram at the end of this section with a simplified event/data flow. Also the project is available on GitHub.
The repository serves as the communication bridge between the data and the rest of the app. Building a Foo feature, the
FooRepository abstracts the data source(s) from the
FooViewModel, while providing the necessary Observables to stream data to the latter.
On the other hand, the ViewModel should bridge the Repository and the View, this is also where your Business Logic lives, much like a Presenter in MVP or a Controller in MVC, but with some key differences, we’re extending the framework’s own
arch.lifecycle.ViewModel class, which has some internal lifecycle awareness, making our development a little less painful, but more on that later.
FooView will hold a reference to the corresponding
FooViewModel instance, getting this is as simple as calling:
viewModel = ViewModelProviders.of(this).get(FooViewModel.class);
Note: ViewModel objects are scoped to the
Lifecyclepassed to the
ViewModelProviderwhen getting the ViewModel. The ViewModel stays in memory until the
Lifecycleit’s scoped to go away permanently—in the case of an activity, when it finishes; in the case of a fragment, when it’s detached.
The next and final step is to subscribe to the ViewModel’s exposed data observables, display the data coming in, and report the user actions back to the ViewModel.
That’s it, no need to have a huge amounts of callbacks, keeping your views (as always) logic free, but now less verbose, therefore easier to maintain 👍.
Using this structure enables our code to be more reusable/modular, when compared to other patterns.
With the new android architecture components writing tests 👈 and separation of concerns is easy as 🍰.
LiveData<T>: Is a data holder class that keeps a value and allows this value to be observed. Unlike a regular observable, LiveData respects the lifecycle of app components, such that the Observer can specify a Lifecycle in which it should observe.
Android’s ViewModel gives us a lifecycle aware component, without the need of holding a reference to a View (e.g Activity, Fragment), more susceptible to leaks. However it will take ownership of the data, therefore we must focus on exposing the right data and work on the Business Logic.
Note: Since the ViewModel outlives specific activity and fragment instantiations, it should never reference a View, or any class that may hold a reference to the activity context. If the ViewModel needs the
Applicationcontext (for example, to find a system service), it can extend the
AndroidViewModelclass and have a constructor that receives the
Applicationin the constructor (since
UPDATE 🔑 — New name: Transport ETA
This project will be redone in full on my coding stream
I decided to stream myself building an app with more complex tools and engineering paradigms from the ground up, this is the project I decided go with, not that makes any difference but I’ll make it an MVP, release but in the end will be an app built with: CLEAN architecture, Reactive and Tested app written in Kotlin only.
Uses SMS-Token service or the web to request a more precise ETA of a public-transport (Bus, Boat etc.) to a specific station, currently implementing for Lisbon 🇵🇹, but the idea is to scale up to any other cities around the world that provide the same kind of service(s). Most of the complex stuff will happen on the backend anyway — yay 🙌 Cloud Functions for Firebase. Writing a well cared reactive android client codebase should be enough to adapt.
Currently written in Java, but will most likely become Kotlin only on new classes/features.
The Data and Ui are in separated parts, imho it’s a crucial way to keep yourself form doing spaghetti code. Using the observer pattern has its advantages since we can simply open channels streaming data and then listen. Sounds awesome (and it is) but, if you’re not careful, you’ll start losing control of your own code 😣.
I’ve placed each ViewModel class inside of it’s
ui/foo package, but it would be correct to have these on a separate viewmodel package at root-level along with repository and ui. I’m still experimenting to see if makes sense, if so, I’ll change it. Feel free to leave your opinion down below 👍.
There’s also a repository for each context, this will further help to archive the app’s complete abstraction from the data-source(s). And these can also be used by different ViewModels since the sole responsibility is to provide (specific) data.
At the moment the web-service responses are mocked, with MVVM or any other battle tested pattern, anything outside of the scope of this article is virtually meaningless, that’s the beauty of a good software architecture.
Note: As mentioned above, the open sourced code isn’t 100% implemented, there is a List and Detail screens (with a list of Stations belonging to the specific bus, demoing relation), this is purely to show Room’s implementation. I might update the project in the future, but I think there is enough there to understand the AACs.
Bye bye Presenter. Hello ViewModel.
Let’s start looking at our
As you can see the
ViewModel has no idea to whom might subscribe to the emitted data. It is also completely abstracted from the data sources, it simply asks the
BusRepository for the data and doesn’t really care of it’s internal implementations, it could come from a remote webservice or a simple local database (this is oddly satisfying to know we’re respecting the Single responsibility principle).
So now looking at our
Take this code with a grain of salt, it might not be 100% correct, and it’s quite complex, for example it could make sense to have a separate class to do Local Database (Room) operations.
The repository returns LiveData that is directly linked to the database, keeping it as the single source of truth. As mentioned before, we’re using the observable pattern so we’re sure every change gets propagated up the stream, preventing re-queries to the database.
Also notice how the responsibilities are, once again, delegated to the respective classes. The repository only gets the
busDao, the only way to get database access, and the remote repository, the entity that deals with all the webservice request/response handling logic.
Finally our simple
BusListActivity → the LifecycleOwner
Also notice I’m not extending the documentation referred LifecycleActivity. This was actually a test, and it works! Most on-going projects will probably have a big difficulty to extend a new classes (LifecycleActivity/LifecycleFragment), so this solution seems to work, just copy the
LifecycleRegistry (gist’s line 5) and the
For more examples look at the GitHub repository, there’s also Room code there, I didn’t dwell much on it here. Imo it is a whole other chapter on itself.
For any other details code related you can always ask here or hit me up on Twitter. I don’t think the focus of this article should be the LoC but the implementation of these new awesome tools, so I didn’t shown a lot of code, there are other articles here on medium who focused more on that.
I highly recommend you to watch the resources posted bellow 👇!
- Architecture Components — Introduction (Google I/O ’17) — IO17 Youtube video
- Architecture Components — Solving the Lifecycle Problem (Google I/O ’17) — IO17 Youtube video
- Architecture Components — Persistence and Offline (Google I/O ’17) — IO17 Youtube video
- Android Architecture Components official page
- Architecture Components: Improve Your App’s Design — 5 minute Youtube video by Lyla from Google
- Room Persistence Library — Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.
Joaquim Ley (@JoaquimLey) | Twitter
The latest Tweets from Joaquim Ley (@JoaquimLey). I create bugs on #Android for a living at @Tonsser. Besides coding…
If you liked this article hit that 💚, if you know someone who might extract value please share, I’ll be looking for your opinion and suggestions in the comments, feedback is always welcome.
If you would like to see more content from me, 👊 the follow button!