How AndroidX changes the way we work with Activities and Fragments

Miłosz Lewandowski
5 min readFeb 5, 2020

--

Photo by Tim Swaan on Unsplash

The article is based on the talks about what’s new in AndroidX I gave at the GDG Devfest 2019 events in Wrocław and Warsaw.

Over the last couple of months, many improvements to the Activity/Fragment APIs have been introduced via the AndroidX packages. Let’s see how they contribute to the state of Android development and how they fit into popular programming rules and patterns.

All of the features described in the article are now available in stable AndroidX packages and were released or moved to stable over the last year.

Layout resource ID in the constructor

Starting with AndroidX AppCompat 1.1.0 and Fragment 1.1.0, you can use the constructor that takes layoutId as a parameter:

This approach can reduce the number of method overrides in your Activity/Fragment and make your classes more readable. There’s no need to override onCreate() in your Activity only to call setContentView() method. Also, there’s no need to override onCreateView() in your Fragment just to manually call the Inflater to inflate the view.

The flexibility of extending the Activity/Fragment behavior

With new APIs available in AndroidX, the shift is to reduce the Activity’s/Fragment’s direct responsibility of handling some of the functionalities. Instead, they can be provided via external classes. In general, the pattern is that instead of overriding methods in Activity/Fragment, you can obtain the object that provides some functionality and register your handler to it. In that way, you can now compose your screen of several independent classes, achieve higher flexibility, reuse the code, and, in general, have more control over the code structure without introducing your own abstractions. Let’s see how this works on two examples.

OnBackPressedDispatcher

Sometimes you need to prevent a user from going back in the navigation stack. In such a case, you needed to override the onBackPressed() method in your Activity. However, there’s no direct way to intercept the behavior when you’re using Fragments. There’s just no onBackPressed() method in the Fragment class available, and that’s to prevent the unexpected behavior when more than one Fragment is available at the same time.

However, starting with AndroidX Activity 1.0.0, you can use OnBackPressedDispatcher to register your OnBackPressedCallback in any place of your code where you have access to the Activity, for example in the Fragment:

You may notice two additional useful features here:

  • the boolean parameter in the constructor of OnBackPressedCallback helps to turn on/off the back press behavior depending on the current state,
  • the optional first parameter of the addCallback() method is the LifecycleOwner to ensure that the callback will be used only when your lifecycle-aware object (e.g. Fragment) is at least in the STARTED state.

By using OnBackPressedDispatcher, you not only get the convenient way of handling the back presses outside the Activity. Depending on your needs, you can define the OnBackPressedCallback wherever you want, make it reusable or do whatever you want to fit your app’s architecture. You’re no longer bound to override the onBackPressed method in the Activity or to provide your own abstraction to achieve the code structure you need.

SavedStateRegistry

If you want your Activity to restore its state after the process is killed and started again, you may want to use the “saved state” functionality. Previously, you needed to override two methods in the Activity: onSaveInstanceState and onRestoreInstanceState. You can also access the restored state in the onCreate method. Similarly, in Fragment, you have onSaveInstanceState method available (and the restored state is available in the onCreate, onCreateView, and onActivityCreated methods).

Starting with AndroidX SavedState 1.0.0, which is the dependency of the AndroidX Activity and the AndroidX Fragment, you get access to the SavedStateRegistry which utilizes a similar mechanism as the OnBackPressedDispatcher described previously: you can obtain the SavedStateRegistry from the Activity/Fragment and then register your SavedStateProvider :

As you can see, SavedStateRegistry enforces you to use the key for your data. This can prevent your data from being corrupted by another SavedStateProvider attached to the same Activity/Fragment. And as in the OnBackPressedDispatcher, you can, for example, extract your SavedStateProvider to another class, make it work with your data by using whatever abstraction you want and in such a way achieve the clean saved state behavior in your application.

Also, if you’re using ViewModel in your application, consider using AndroidX ViewModel-SavedState to enable your ViewModels to save their state. And for your convenience, starting with AndroidX Activity 1.1.0 and AndroidX Fragment 1.2.0, the SavedState-enabled SavedStateViewModelFactory is the default factory used across all ways of obtaining ViewModel: delegates, ViewModelProvider constructor and the ViewModelProviders.of() method.

FragmentFactory

One of the most mentioned issues with Fragments is no possibility to use a constructor with arguments. For example, if you’re using Dagger2 for dependency injection, you cannot annotate the Fragment constructor with Inject and specify the arguments. Now, you can mitigate this and similar issues with Fragment creation by specifying the FragmentFactory class. By registering FragmentFactory in your FragmentManager, you can override the default way of instantiating the Fragment:

As you can see, the API is very general, so it gives you the ability to do whatever you want to create the Fragment instance. Going back to the Dagger2 example, you can, for example, inject to your FragmentFactory Provider<Fragment> and use it to obtain the Fragment object.

Testing Fragments

Starting with AndroidX Fragment 1.1.0, the fragment-testing artifact is available, providing the FragmentScenario class that can help in instantiating the Fragment in your tests and testing it in isolation:

More Kotlin!

It’s nice to see that many useful Kotlin extension methods are available in the -ktx AndroidX packages and the new ones are added regularly. For example, in AndroidX Fragment-KTX 1.2.0, the extension that uses reified type is available for the replace() method on FragmentTransaction. Combining it with the commit() extension method, we can get the following code:

FragmentContainerView

Just a small but important thing to mention. If you’re using FrameLayout as a parent to your Fragment, you should switch to FragmentContainerView instead. It fixes some animation z-index order issues and window insets dispatching. The FragmentContainerView is available starting with AndroidX Fragment 1.2.0.

What’s coming next?

Well, one can speculate, but nobody knows until it’s released! However, as you can see, it’s worth to check from time to time what’s new in AndroidX packages and how the changes can improve your day-to-day life as an Android developer.

--

--

Miłosz Lewandowski

Senior Android Developer at Miquido — mobile apps design & development