开发者

MVC in Android: Application or Service for asynchronous updates?

开发者 https://www.devze.com 2023-01-05 19:48 出处:网络
(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.

(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 display Model from different perspectives. Currently I have a ListActivity for all elements, and an Activity for one element's details
  • Sometimes Model needs refreshing. Surely this is done on a different thread. Refreshing can be triggered from several Activity's.
  • There are several (time consuming) common tasks that can be triggered from different Activity's
  • My application loads and saves Model to 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 Service and send broadcasts. Saving to disk is performed in Service#onDestroyed(), so I want to minimize that by binding it to Activity's. At this point, I'm also not sure how to deliver the updated information: whether to provide a getter in Binder, or include that in the broadcast message.
  • Customize the Application object so that refreshing methods and getters are available globally. I then perform update from Activity's using AsyncTask. If there are other Activity's that are behind the current Activity, they will update in onResume() when the user navigates back.

Reasons I'm not using a class with static methods:

  • I need to save and store Model to 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
     开发者_C百科           }
                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.


Services are mostly suitable for something that is not bound to a single Activity (and usually work together with NotificationManager or a Widget). This doesn't seem to be the case.
So my suggestion is to have a well-engineered AsyncTask that manages state via SharedPreferences/SQLite itself (instead of abusing Applicaion) and will be launched from the ListActivity.


Well, you could extend a BroadcastReceiver instead of a Service, and when it's done doing what it needs to do, it loads up an Activity with the results.


You didn't explain what kind of info are you getting but this line is important:

These tasks involve states that need to be loaded and saved gracefully when the application starts and stops

If that is the case, why don't you do an AsynTask inside the Activity?

I had your same worries about sending Intents with ArrayList inside but I have an app which does exactly that and I am not having performance issues.

0

精彩评论

暂无评论...
验证码 换一张
取 消