Decoupled Activities

Every now and then, somebody asks on StackOverflow or somewhere else about how to parcelize some nasty data structure, because they want to pass it from one activity to another.

Generally, this is a really bad idea. What confuses me is that it should be fairly obviously a bad idea, since the design principles have been pounded into developers’ heads for the past decade or so.

“Wait!”, you say. “Android hasn’t been around for ‘the past decade or so’!”. ‘Tis true. However, the design principles behind activity coupling are damn near identical to the design principles for coupling between Web pages of a Web app.

When you get right down to it, activities and Web pages are, architecturally, rather similar:

  • They appear on a stack, with one visible at a time, and use a BACK button for reverse navigation through the stack.

  • A page/activity can transfer control to another page/activity via a “link” (<a> element in HTML, Intent in Android) that is passed to the hosting environment (browser, Android) that arranges to display the new page/activity.

  • No page/activity can directly interact with the other, assuming you’re playing by the rules.

When writing a Web app, each Web page has some amount of model data, perhaps a table of items, or perhaps a detail form for modifying an item. However, the Web page itself is not the model — the model is held and managed by a Web server. The table-of-items Web page does not persist the entire MySQL database into the URL used to link to the next Web page. Rather, the table-of-items Web page provides just enough identifying information to tell the next Web page what to do, such as the primary key of whatever item it should display in a detail form.

Activities should be designed the same way. Use Intent extras to pass the same sorts of things you would pass in HTTP GET parameters, such as keys. However, the model data should be in a centralized store:

  • Database
  • Database fronted by a ContentProvider
  • Service providing an API for accessing a set of model objects persisted by one means or another
  • Custom Application object providing an API for accessing a set of model objects persisted by one means or another
  • Static singleton object providing an API for accessing a set of model objects persisted by one means or another
  • Etc.

Think of your activities as Web pages and think of your centralized store as being your Web server.

If you have two activities that are tightly coupled working with in-flight data not ready to go into the model, perhaps they should not be separate activities. For example, I would not recommend implementing an editing wizard as a set of activities — rather, use a ViewFlipper to implement a wizard GUI within a single activity, so your editing operation is in that one activity.

There will always be exceptions to every rule — that’s half the reason the rules exist in the first place. But seriously reconsider passing around your data model via Intent extras — that’s not how you would do it on the Web, and it’s probably not how you should do it in Android.

Find out about new posts on the CommonsBlog via the Atom feed, or follow @CommonsWare on Twitter!