Everything that’s wrong with Android’s Activities

Niek Haarman
5 min readAug 27, 2018

--

..and Fragments, for that matter.

Let’s just kick off and have a look at what an Activity is capable of:

1. The Activity is an entry point

The Activity is an entry point into your application that the user sees when they open your application. Upon clicking your application icon from a launcher app, an Activity instance is created and presented to the user.

2. The Activity hosts the window that interacts with the user.

By calling setContentView in your Activity, you can inflate a layout that is bound to a Window instance hosted by the Activity. This allows the user to see and interact with your application.

3. The Activity has a lifecycle

Android’s multitasking mechanism allows for applications to be put in the background temporarily, and navigated back to when the user sees fit. To be able to react to these events, the Activity provides a set of callbacks you can implement.

4. The Activity needs state restoration

Android’s multitasking mechanism combined with limited memory can cause applications to be killed. To prevent a bad user experience when the user loses a message he or she was typing due to this, the Activity allows its state to be saved to a bundle.

5. An Activity can have a result

Applications can start other applications to request a particular result. For example, the Contacts app can be launched to select a particular contact. When this is done, the result is sent back to the original application that started the request.

Now these are all very valid use cases. They make up the foundation of all applications, and allow for perfectly fine applications to be created.
But wait, there’s more!

6. The Activity is destroyed on configuration changes

When a device configuration changes, such as an orientation change or when the system local has changed, the Activity is destroyed and recreated with a new Resources set for the new configuration.

7. The Activity handles navigation

When a user clicks an item in an item list Activity, the Activity can start a new Activity to show the item’s details using startActivity.

8. The Activity handles permissions

When your application wants to read a user’s location info for example, you need to call Activity#requestPermissions. Your Activity will receive the result in Activity#onRequestPermissionsResult.

9. The Activity hosts an options menu

Earlier versions of Android had a dedicated ‘menu’ button that would popup a menu in the application. To populate this menu, you override Activity#onCreateOptionsMenu; when a menu item has been selected, Activity#onOptionsItemSelected will be called which you can override.

10. The Activity hosts an ActionBa.. Toolbar

When the options menu button disappeared from devices, the ActionBar class appeared to be able to host this options menu. You can set a Toolbar using Activity#setActionBar.

11. The Activity has direct references to the View hierarchy

To show meaningful content to the user, you can use Activity#findViewById to fetch a certain View and populate it with data.

12. The Activity can handle key presses and touches

Just override Activity#onKeyDown or any of its siblings.

13. The Activity can handle voice interaction

I’m not even sure what this is. Here’s a reference.

14. The Activity provides Activity-private preferences

Calling Activity#getPreferences returns a SharedPreferences instance private to the Activity.

The above is a subset of what android.app.Activity can do, and I’m sure I have forgotten a few major use cases. On top of all this FragmentActivity can also host Fragments and by the way, Fragments are designed to be able to do everything an Activity can do!

Now what’s wrong with all this?

All these points are perfectly valid features. You need new resources on configuration changes, you need to handle navigation, you need to handle permissions, etcetera.

However, having to resort to the Activity to do all these things severely violates any kind of single responsibility principle. The Activity is a God class and all of its subclasses are prone to become God classes themselves as well.

All of a sudden your screen logic needs to stop whatever it is doing and be recreated because someone rotated their device.
Handling complex navigational patterns suddenly resides in the screen as well because, well, the back stack.
Working with UI elements like options menus, toolbars, even key presses or touches are all view-related and have no business near any useful logic.

Then there are problems with what they can’t do. The most obvious one here is transitions between screens. With multi-Activity applications, it is very hard to have proper and fine grained control over your screen transition animations.

Inversion of control

With the latest trend of using single Activity apps, the Activity should have a very simple purpose: hosting the UI. Everything else, from callbacks to navigation and state restoration belong in different components. Unfortunately, that is not the way Android works, and you’ll have to deal with it.

That doesn’t mean that you have to bind all your logic to it though.
When writing software, your business logic is the most important thing in the world. Everything you (or your team) didn’t write yourself is out of your control, and you should protect yourself from it. Obviously this includes the Android framework.

Protecting yourself from third party software means that that third party software cannot break your business logic. If there’s a bug in the Android framework, or a third party library breaks, you shouldn’t have to alter your core logic to fix the problem.

The plugin model

The de facto standard for this is the plugin model. You let the GUI be a plugin to your application. The database is a plugin to your application. Then, when there is indeed a bug in the Android Framework, you still have to create a workaround. But instead of the Android Framework leaving its marks in your precious business logic, this will all be at the very boundaries of your system.

Android as a plugin to your application.

Note that the GUI is just that: the Graphical User Interface. Or in Android terms: everything that extends the View class. Navigation, screens, presenters and everything else is business logic that you want to have testable and far out of reach from the complex intricacies the Android Framework provides.

It’s time to take back control over our applications and shove the monolith classes that Activities and Fragments are aside until they’re absolutely necessary.
When you do this, you can write your core application logic in pure Java. Or Kotlin even. And what about Kotlin Native?

--

--