Using Android Fragments in 2018
No, I’m not crazy. And yes — I know there are dozens of frameworks and approaches that are trying replace them.
At INLOOPX we are building Android and iOS applications that may take months or years in continuous development, where an application may need to be supported for a long-term, where the developers may change. The client may even take our source code and continue with the development in-house. I think all of these are factors that come into play if you are choosing a technology stack for your app.
Using standard tools (such as Fragments) may sometimes be boring, it’s not cutting edge, but on the other hand everyone knows them. Onboarding a new developer is much easier. Fragments have existed for years (back in the days the support library backported them to Android 1.6) and Google continues to improve them. And actually there has been a lot of new stuff added recently, including ViewModels and LiveData which play very well with Fragments.
The Fragment stigma
Fragments have been frowned upon many times and often rightfully so. There were some bugs — most of them fixed thanks to the support library. But often times people were using them just in very wrong ways. Google gave the developers too many options to choose from and some pieces were just missing.
There is one BIG cause of many problems with Activities and Fragments, Jake nailed it in this tweet:
And speaking about Google examples — remember the time when running an AsyncTask in Fragments was totally okay? Google actually offered several tutorials on this. How do I preserve the asynchronous task during orientation changes? What do I do if the result is delivered after the Fragment is in a stopped state? What if the result is delivered too late? There were so many things that could go wrong and everyone tried a different approach. Google offered the LoaderManager approach, which was viewed mostly as a failed abstraction, and just too complex, or using retained fragments, or using
onRetainNonConfigurationInstance() to transfer the task through the orientation change.
The solution is simple — just don’t do it :-). Do not put any kind of this business logic and asynchronous work into your fragments since it will never play well with the Fragment/Activity lifecycle. ViewModel is the place where you want to put that code.
Why use Fragments at all?
There is a misconception that either everything in your app is made of Fragments or you choose an other route (like, for example, views).
Fragments provide glue and coordination of components, driven by knowledge of external lifecycle. Fragments can depend on Views. But Views have no knowledge of Fragments.
Don’t use a Fragment if a Composite View does the same job, especially if you don’t need any lifecycle callbacks (e.g. that UI doesn’t need to know when the app is paused). On the other hand don’t do stuff like binding to a service inside composite views (ViewGroups), listening to broadcasts, and other things where you are bringing external dependencies into your custom view. This is again better suited for Fragments.
Fragments provide you with a backstack, state restoration (remember that dreaded process death?), transitions, animations, options to detach/re-attach views, the whole lifecycle awareness and much more. They are usually self-contained, and are also great for 3rd party libraries — where the developer can just drop in your Fragment into an XML, and little or no integration is needed.
ViewModels to the rescue
Google should have done this much sooner. But, better late than never. ViewModels are part of Architecture Components, and are used to keep all the UI related logic, state and manage it. Fragments and Activities are now mostly reduced to just displaying the current application state (represented by the ViewModels). All the orientation change headaches are gone — ViewModel instances survive them and are not affected. You should really be using ViewModels or similar patterns with Fragments (and Activities) the code will get very messy without them.
In fact, we made our own AndroidViewModel library 2 years sooner at Inloop. I wrote an article about it. We’re flattered that Google’s implementation is very similar to ours.
ViewModels are really simple and elegant, Google went with the KISS approach here. There is only ONE lifecycle callback inside the ViewModel —
Of course, ViewModels are not exempt to “nuances” that the Android platform brings. They will survive orientation changes, but are affected by the process death as everything else (check out my article about it). You have to store your Fragment/Activity state in the corresponding
onSaveInstanceState() callback and/or just load everything from scratch (using the arguments from your Bundle). This isn’t an issue though — just something to be aware of.
By the way — have you ever wondered what mechanism ViewModel uses to survive orientation change? They’re kept inside headless retained Fragments during the orientation change. Pretty neat. But for the love of God, don’t use Retained Fragments in regular screens. They’re not really meant to be used with an actual UI.
But, but… Fragments are complicated!
The API can be overwhelming at times but you don’t actually need to use all the lifecycle callbacks and API methods. Use the minimum you need. But it’s good to know that they cover a lot more than these basics.
Doing an application from scratch from composite views sounds like a good idea at the beginning. But then you’ll find yourself battling complicated issues — implementing your own custom backstack implementation, state restoring, and process-death handling, animations, transitions… You’ll mostly end up with something half-baked, and proprietary, and most possibly even worse and more complicated than Fragments in the end.