Or: How I stopped worrying and learned to love Fragments.
Fragments have been a contentious topic in the Android developer community pretty much since they were first introduced. Ever since I read Square’s influential blog post, Advocating Against Android Fragments I have been firmly in the anti-Fragment camp. Recently, I’ve had cause to revisit Fragments. As it turns out, I think it might be time to switch sides.
In this post, I review the main problems with Fragments, then look into some of the recent changes that have alleviated those issues.
What was wrong with Fragments anyway?
When Fragments were first introduced way back in 2011, the main goal was to have a mechanism for creating modular, reusable, and largely self-sufficient components. This was an excellent goal, but the problems quickly arose. As I see it, the main issues were as follows:
- Fragments had a lot of responsibilities to support, which made them challenging to implement correctly. E.g. lifecycle management, navigation state, composition, helping manage async operations.
- The lifecycle was very complicated (see here) especially when you consider that there were differences in behaviour between different Android versions.
- The implementation was buggy, and some areas (notably nested Fragments) suffered from a host of lingering issues. Often the bugs only arose in edge cases, and were very tricky to work around.
So what has changed?
In the past couple of years Google has doubled down on Fragment support, and they have made this clear at Google I/O ’17 and ’18. Fragments are being given a central role in the new Architecture Components libraries, and Google are now advocating a single-Activity, multi-Fragment architecture.
Google have clearly been putting concerted effort into fixing bugs. I’m not going to try to list all of the issues that have been addressed, but in my investigations the only issues I came across have already been resolved in the AndroidX 1.0.0-beta builds.
New library support
Many of the new Architecture Components are designed to handle a smaller subset of the responsibilities owned by Fragments - we now have straightforward, “official” means of delegating the responsibilities out to other classes. They also smooth over a lot of the tricky edge cases that users of Fragments have previously had to deal with. Taken collectively, they have a massive impact on how easy it is to work with Fragments.
For me, the main benefit of the Lifecycle library is that it manages to put a simplified, clean and consistent wrapper around the mess that exists under the hood. It is simplified to something like this:
Google have even taken steps to ensure that
onSaveInstanceState() is called at a consistent point in the lifecycle. (See here). Also, in the AndroidX 1.0.0 release, Google have seen fit to recognise that the Fragment’s View has its own lifecycle. (See here.)
Previously, in order to write a well-behaved Fragment you essentially needed to implement a state machine which could keep track of multiple system callbacks to determine how to act appropriately. As far as I can see, we’ve now moved to a situation where we don’t need to track any state internally. This is a huge win in terms of ease of implementation.
I find the name confusing, but ViewModels are great. In essence, they give you an object that is bound to the logical lifecycle1 of a Fragment (or an Activity). It’s great to finally have an “official” mechanism for this.
The ViewModel becomes the owner for the transitive state of the Fragment, including asynchronous operations.
Lets you perform async operations without having to worry about memory leaks or updating he UI after
Honestly, I haven’t looked into this one in detail yet, but its role is to take over navigation responsibilities from the Fragment which definitely a good idea.
I still don’t have enough real-world experience with the new libraries to make a decisive call. I certainly don’t think Fragments are perfect - even with the new libraries, there are some wrinkles remaining. There are other things I still haven’t figured out yet, like the best approach to testing. What I will say is that I am very encouraged by my experience so far. Using the new libraries, it is now possible to write lightweight Fragments which just do I’m tentatively changing my assessment of Fragments from “actively harmful” to “actually useful”.
It’s worth mentioning that there are still perfectly sound - possibly better - alternatives. You can stick with Activities, use a library like Conductor, or roll your own solution. The playing field isn’t exactly level though: many teams will use Fragments simply because they are Google’s recommended approach. (I make no judgements here - there are valid reasons for doing this.)
If, like me, you hated the ‘old’ Fragments, I’d encourage you to try the ‘new’ ones. You might be surprised! You’re likely to need to use them sooner or later, so I think it’s worth getting comfortable with them.