(I'm sorry for not being so clear in my first post)
Here is the situation: I have data that is to be refreshed from the Internet. Let's call it Model.
What I want to do: Basically it sounds like an MVC model, where the Model is also kept persistent in local (private) storage. The Model and its associated methods are application-wise. There are several Activity's that display and manipulate different aspects of it:
- User
navigates across different
Activity's that displayModelfrom different perspectives. Currently I have aListActivityfor all elements, and anActivityfor one element's details - Sometimes
Modelneeds refreshing. Surely this is done on a different thread. Refreshing can be triggered from severalActivity's. - There are several (time consuming) common
tasks that can be triggered from different
Activity's - My application loads and saves
Modelto private storage when it starts and stops
My problem: I'm not sure where to put Model and the related tasks in. Also, I don't know what mechanism to use to notify Activity's. Currently I come up with 2 approaches:
- Use
Serviceand send broadcasts. Saving to disk is performed inService#onDestroyed(), so I want to minimize that by binding it toActivity's. At this point, I'm also not sure how to deliver the updated information: whether to provide a getter inBinder, or include that in the broadcast message. - Customize the
Applicationobject so that refreshing methods and getters are available globally. I then perform update fromActivity's usingAsyncTask. If there are otherActivity's that are behind the currentActivity, they will update inonResume()when the user navigates back.
Reasons I'm not using a class with static methods:
- I need to save and store
Modelto disk. - Some of the methods need a Context for displaying toasts, notifications, caching, etc.
Also, I don't put these functionalities in an Activity because there are several activities that manipulate the same piece of persistent data.
Below are pseudocode illustrating what I mean:
Using Service:
/** Service maintaining state and performing background tasks */
class MyService extends Service {
Model mModel;
Binder mBinder;
onCreate() {
super.onCreate();
mBinder = new Binder();
// load mModel from disk, or do default initialization
}
onDestroy() {
super.onDestroy();
// save mModel to disk
}
onBind() {
return mBinder;
}
class Binder {
refresh() {
new AsyncTask() {
doInBackground() {
// update mModel from Internet
}
onPostExecute() {
sendBroadcasts(new Intent("my.package.REFRESHED"));
}
}.execute();
}
getState() {
return mModel.getState();
}
}
}
/** Activity displaying result */
class MyActivity extends ListActivity {
MyService.Binder mBinder;
onCreate() {
super.onCreate();
// register mReceiver
// bind service
}
onDestroy() {
super.onDestroy();
// unbind service
// unregister mReceiver
}
/** Invokes time-consuming update */
refresh() {
// binding is asynchronous, and user may trigger refreshing too early
if (mBinder != null) {
mBinder.refresh();
}
}
BroadcastReceiver mReceiver = new BroadcastReceiver() {
onReceive(Intent intent) {
if ("my.package.REFRESHED".equals(intent.getAction())
&& mBinder != null) {
updateViews(mBinder.getState());
}
}
};
}
Make the functionality globally accessible in the custom Application object
/** Custom Application providing domain specific functionalities */
class MyApplication extends Application {
Model mModel;
onCreate() {
super.onCreate();
// load mModel from disk, or do default initialization
}
onTerminate() {
super.onTerminate();
// save mModel to disk
}
void refresh() {
/** time-consuming */
}
getState() {
return mModel.getState();
}
}
/** Activity displaying result */
class MyActivity extends ListActivity {
onResume() {
super.onResume();
// in case some top Activities have refreshed
// and user is navigating back
updateViews(((MyApplication)getApplicationContext()).getState());
}
/** Invokes time-consuming update */
refresh() {
new AsyncTask() {
doInBackground() {
((MyApplication)getApplicationContext()).refresh();
}
onPostExecute() {
// update the ListView according to result
updateViews(((MyApplication)getApplicationContext()).getState());
}
}.execute();
}
}
Weaknesses I can think of for the Service approach is complexity, since Binding is asynchronous. And it's very likely that I have to repeat some code because I have both ListActivity and Activity
For the Application approach, the documentation says not to rely on onTerminate() being called.
I know I'm being very awkward. What is the conventional way to solve this sort of problem?
Many thanks.