views:

150

answers:

4

I've got a common task that I do with some Activities - downloading data then displaying it. I've got the downloading part down pat; it is, of course, a little tricky due to the possibility of the user changing the orientation or cancelling the Activity before the download is complete, but the code is there. There is enough code handling these cases such that I don't want to have to copy/paste it to each Activity I have, so I thought to create an abstract subclass Activity itself such that it handles a single background download which then launches a method which fills the page with data.

This all works. The issue is that, due to single inheritance, I am forced to recreate the exact same class for any other type of Activity - for example, I use Activity, ListActivity and MapActivity. To use the same technique for all three requires three duplicate classes, except each extends a different Activity.

Is there a design pattern that can cut down on the code duplication? As it stands, I have saved much duplication already, but it pains me to see the exact same code in three classes just so that they each subclass a different type of Activity.

Edit: Since it seems I need to be a bit more specific...

Suppose I'm trying to solve the problem of an AsyncTask background download during orientation changes. The solution I have right now is to use callbacks; there's download manager that I have which starts these downloads, and then I have the Activity attach a callback to it. When the orientation changes the Activity is destroyed and then recreated; during this process I detach the old Activity's callback, then attach a new callback from the new Activity afterwards.

Orientation changes are a common problem, and in multiple Activities I start the Activity with a progress view while the data loads. What I am trying to solve is not having to re-implement this orientation-handling logic ten times over; my initial solution was to subclass Activity, but then I got the problem above.

+3  A: 

Prefer composition over inheritance. Whatever is common, delegate to some class(es) that can be a member of Activity, ListActivity, and MapActivity.

Carl Manaster
I understand this concept perfectly, but doing composition in this case would mean just about as much code duplication as simply implementing it in each class. Each class would have to implement onCreate(), onRetainNonConfigurationInstance(), onResume(), onPause(), onDestroy() and call the delegate. I would prefer not to have to think about this implementation aspect for each Activity I write. I could be convinced otherwise but in this case composition results in just as much duplication, unless there's something I'm missing.
Daniel Lew
Ick. That suggests that android's Activities are too large, and you probably have no control over that. I suppose you could write a DelegatingActivity with those functions (and assignDelegate() or somesuch) already written, and inherit from that. As you've described it so far, that doesn't have much advantage over a plain Activity interclass, but it could pay off down the road.
Carl Manaster
The way that Activities work is that they have different methods that are called at different states (e.g. "onCreate()" and "onDestroy()"). When you implement your own Activity, you sublcass and extend these methods in order to define behavior.Your post has given me an idea, which is to still create multiple subclasses of various Activities, but to have each implement a delegate inside of it; that way I'm not implementing the same code each time. Still, I was hoping for a slightly less messy solution.
Daniel Lew
I'm going to mark this as correct, because ultimately reading this opened me up to a slightly different (though still vaguely repetitious) answer that is less problematic than before. Not a perfect answer, but better.
Daniel Lew
A: 

The problem is that you are mixing view and the logic of your program. A background thread like an AsyncTask will run as long as your application is not killed from the system. You could do the download everything in the async task and then save it somewhere on the SD-Card to retrieve it from there if it is ready.

You could subclass the application class to hold a reference to the task or a handler to communicate with the class from every Activity.

If this is not a solution to your problem at all maybe you could clarify the question a little bit. It would help to know what you are doing in the onCreate... methods.

Janusz
I think you've got a narrow view of what I have setup already. :) I've written a library for downloading in the background via AsyncTask, however such a library cannot account for issues like Activity destruction/recreation through orientation changes. When the orientation changes, I have to be able to re-attach the Activity to the download already in progress (in my case, by setting a new callback). The code I'm talking about reducing duplication on is this code; every Activity must handle orientation changes, and since it's the same code between each I want to just reuse.
Daniel Lew
I still don't get what you are doing in all the onresume ondestroy etc activities, maybe you should give some code examples
Janusz
A: 

I haven't used MapActivity, but I solved this problem by not using ListActivity and providing the functionality myself in Activity. There really isn't that much in ListActivity if you look: http://google.com/codesearch/p?hl=en#uX1GffpyOZk/core/java/android/app/ListActivity.java Implement the functionality yourself you get more customization and more room to grow.

Jim Blackler
I thought about your solution, but according to the docs MapActivity cannot be ignored in such a manner: "A MapView can only be constructed (or inflated) by a MapActivity. This is because it depends on threads which access the network and filesystem in the background; these threads must be shepherded by the lifecycle management in MapActivity." (http://code.google.com/android/add-ons/google-apis/reference/com/google/android/maps/MapView.html)
Daniel Lew
A: 

Any way for you to have a helper class with static methods to which you would pass your activities and have the common work done there instead of in each activity?

JRL
Currently I have something like this setup, though by the nature of what I'm doing it has to be an instantiated object not static methods. However, this solution still means you either have to rewrite the same code in every Activity that wants to use this functionality, or you have to subclass each type of Activity in order to reduce code duplication.
Daniel Lew