I am considering how I can add tasks to Android Activities in a flexible way. I can only use implementation inheritance for one thing in Java and I would like to use it, if I use it at all, for something else.
I think I need to draw the domain first a bit:
Activities are UI windows basically, with intrinsic lifecycle responsibilities enforced by the API. The tasks I speak of are UI-visible popovers that do some offline stuff and then disappear. They stem from AsyncTasks. The code of all of this is not a problem, I have this already, even pretty generalized with interfaces. I'm looking at further design improvements I can make.
There are many type of activities and they could all work with some types of tasks. For instance a search window would have a task that adds one of the search results, let's say it's a book, to the collection of books in the main application. It allows you to add multiple, hence the popover. A window that displays the collection has a task that lets you export a book to an external file format. It won't stop you from browsing through your collection, yet it needs to display a progress bar as it may take a while to export.
A specific Task exists as a nested class in a specific Activity. It needs to be saved away and restored along with lifecycle events: there's a
onRestoreInstanceState(Bundle) for that, among others. The Activity has a list of active tasks (or just a member for one task). Some UI event will create a new task and add it to the list, a la
onClick(): ATask task = new ATask(); task.execute(something);.
Here's what I have considered so far:
Just move this task business to an abstract super class of all specific activities.
Create a TaskedActivityDecorator that would add this responsibility on any activity. The decorator would have to mimic the entire Activity interface as provided by the API, mostly passthroughs though. So this may already be a bit too heavyweight. It would also need to add the UI events/buttons that launch the task, which may not always be possible if the action is more consequential.
But the biggest problem I could come up with here is that Android uses a manifest to loosely couple all activities together. Therein you need to declare every specific activity or it can not be used. This is a problem because the decorator would work at runtime, with composition. I can't declare the decorator and add in the information that it needs to wrap a specific activity.
With Android I seem to end up with implementation inheritance a lot more than I'd like to. Hence I have too much coupling or code duplication. The activities always easily grow out to big fat classes. Am I correct to say that that is partly because of existing design choices in the Android framework, such as the manifest taking away composition solutions, or the Context object? Am I correct to say that from the get-go it cuts away a significant amount of established design patterns in key areas, including the MVC pattern.
Decorator with wrappers:
That I can't specify the decorator and the specific activity it applies to together in the manifest, doesn't mean I can't create classes that represent and arrange this composition. I could of course create many SpecificDecoratorActivity classes, that also implement the Activity interface and act like the decorator, and then wrap in the real specific activity. I'm not sure if it solves my problem though. It seems like a lot of work, a lot of rubbish classes, and takes me far from my original goal.
If I can't skin the activity, then I'd better outsource part of its guts. This will give me yet more connections though as the activities will need to know about the Strategy. The Strategy itself however will be more lightweight as a Decorator. Yet it feels not so much like Strategy where there is a choice of which one, but rather just moving part of the class to another class. I would call it TaskManager. And would I still pull up the strategies knowledge into an activity super class?
Any other pattern?:
Which pattern is the best choice? Don't shun your opinion on the specific Android case. No need to talk about tasks specifically.