Android Decompile Deepdive: TED
Android Decompile-Deepdive is a series where we take a popular, successful, impressive application and decompile it, seeing what things we can learn in the process.
Today we’ll be investigating the TED Android App.
We’ll start by checking out the third-party dependencies, and then deep-dive into the CLEAN implementation in the app. Finally we’ll check-out a tip for Null Object pattern in Java as well as UX first impressions.
- BoltsFramework Bolts
- AppBoy SDK
- Comscore SDK
- BrianWernick ExoMedia
- GoogleCast CastCompanion
- JapGolly SvgAndroid
- JgilFelt SQLiteAssetHelper
- Square Picasso
- Square OkHttp
- JakeWharton Timber
- JakeWharton ButterKnife
- Chrisjenx Calligraphy
- Android Support and Google Play Services
- MultiDex Support Library
Not too many surprises here although there are a couple of interesting things. Particularly new for me was the Bolts SDK made by the parse/facebook team. It’s worth checking out, although after some brief investigation it seems DeepLinkDispatch is simpler for deep-links and RxJava is a more feature complete background task and more solution.
CLEAN architecture with MVP
Clean architecture is all the rage these days in the android world. And for good reason. Historically activities and fragments have lead to god-classes that know and do everything. (especially if you try to follow google’s tutorials and examples).
As the Android development community has moved away from MVC with activities functioning as mega view/controller gods, MVP has become a big player.
We’re going to use the TalkDetails screen as an example and check out the presenter, view, interactor, and model layers that power it.
Fair warning, this turned out a bit long. We’ll check out the presenter classes and the view interface definition in them. The view implementation and the XML UI. The interactors and the models behind them.
I tried to make it as concise as possible without skipping over important info, but this small vertical slice of code to show this one screen is actually pretty deep.
Let’s check out the base presenter class for details first.
We pass the interactors (coming up later) in to construct our presenter. Notice there is NO view here as an initialization parameter.
Everything in your presenter should be plain old Java. Unfortunately, as sometime happens in production code, this ideal is violated here with Context.
It does make the presenter a bit harder to test, now requiring Robolectric, and it also could lead to a memory leak if this presenter isn’t dereferenced properly.
All of the presenters in the TED app follow an (unspecified) interface of attach, detach, and present.
In this case because it’s an base class for a group of Detail presenters, the present method is abstract, although it does provide
a presentDefaultUI() method for subclasses to call to handle the common behaviors between all detail presenters.
You can see the callbacks from the View like onClickFavorite. There’s also code here dealing with interactors that is private to the presenter.
The only lackluster thing here (in my opinion) is the android.content.Intent class being all over. I would have preferred the view (or some other class) pulls data out of the intent that is relevant and passes that to the presenter.
The detail view is defined as an interface in the DetailsPresenter. This gives us easy testability and swappable view concretions among lots of other great things.
Let’s check out the XML layout first and then we’ll look at the TalkDetailActivity that implements the DetailView interface defined in the presenter.
There’s not a whole lot to say here about the layout. The only things of real note are the AspectRatioFrameLayout and the ParallaxHeaderRecylcerView, which are both very simple subclasses.
Notice: The view does NOT create presenter and fulfill its dependencies. Instead, the presenter is created via dependency injection outside the view. This is an important detail, so that your view doesn’t have to have access to interactors, or any high-level application components.
After the views have been created and attached, referenced with Butterknife, and presenter resolved, it attaches itself and tells the presenter to present.
Detaching from the presenter happens in the activity onDestroy lifecycle callback.
Why detach? And why detach in onDestroy()?
If you don’t detach your view from your presenter and your presenter is referenced from more than just your view, then you’re creating a memory leak. Leaking context is especially bad in Android, and something you want to avoid.
It makes sense to detach in onDestroy() as that’s what get’s called when the activity is destroyed by the system or you call finish() on it. This isn’t guaranteed to be called by the OS, but in the instances it doesn’t get called the process is killed so the view also be killed anyway.
Interactors (also known as Use Cases)
Here is the GetTalks interactor (one of the interactors used by the TalkDetailsPresenter).
TED is using a pseduo repository pattern. It’s pretty close to being ignorant of where the data comes from (database, http, mock source, etc.)
I also like the abstraction away from concrete platform details (instead of directing resolving to a SQL database or HTTP client from an interactor).
Notice the GetTalks interactor API returns observables. This makes the interactor flexible and enables the interactor’s client to make a lot of decisions.
Client chooses scheduling, threading,error handling, callbacks, etc.
It also gives us the functional style where we can use operators to chain observables together, map and filter data, and do other operations.
Pretty much a typical POJO. Not much talk about here. This is a good thing, this just a business entity.
There should not be anything exciting here. Skinny models are good.
And yes, it’s worth mentioning that in typical CLEAN the model is the code to fetch the models as well, it’s not literally just a model. So typically a TalksRepository is part of the model layer as well.
But again, the interactor coupled with the data layer/model in the TED app.
Null Object Creator
The Null Object Pattern is a cool little pattern that has a variety of use cases.
This is an awesome tiny class from the TED app to create NullObjects for any class.
The TED app uses it for the Views in their presenters.
The presenter view field is by default set to the NullObject implementation, and then is reset back to it after detaching the “real” view.
I’m guessing they do this instead of null checking on view callbacks after long running background tasks. Could also be nice for testing the presenters as well.
Since the TED app has mostly static non-user-specific/private data, it pre-populates the database for the application.
The initial 134KB database includes 2523 talks, 1903 speakers, 421 events, and 372 tags.
This is great from a UX perspective. Instead of counting on internet-access, then grabbing a bunch of data, creating tables, saving entries, and then show your UI they can instantly show the list of popular talks/playlists.
First impressions are hugely important, especially in mobile apps.
TED does a great job here valuing the user’s time and instantly showing them popular content.
The TED app is not only a great application from a UI/UX perspective, the code overall is very simple and easy to understand.
This was a little tough to do, it’s very easy to over or under-describe when talking about a full app architecture like CLEAN. Hopefully, this helped to illuminate what that structure looks like in a live, production app.
Next in the Android Decompile-Deepdive Series:
We deep-dive into their push notification library. It’s conventions, platform and registration handling, and integration.
Enjoy the snippets?
Disagree with my analysis?
Have burning-hot fiery opinions about some random sentence above?
I’d love to hear from you, leave your comments below!