40

I have a data loading system set up using a custom Loader and Cursor that is working great from Activities and Fragments but there is no LoaderManager (that I can find) in Service. Does anyone know why LoaderManager was excluded from Service? If not is there a way around this?

Alex Lockwood
  • 81,274
  • 37
  • 197
  • 245
David Sauter
  • 503
  • 1
  • 4
  • 9

2 Answers2

53

Does anyone know why LoaderManager was excluded from Service?

As stated in the other answer, LoaderManager was explicitly designed to manage Loaders through the lifecycles of Acivities and Fragments. Since Services do not have these configuration changes to deal with, using a LoaderManager isn't necessary.

If not is there a way around this?

Yes, the trick is you don't need to use a LoaderManager, you can just work with your Loader directly, which will handle asynchronously loading your data and monitoring any underlying data changes for you, which is much better than querying your data manually.

First, create, register, and start loading your Loader when your Service is created.

@Override
public void onCreate() {
    mCursorLoader = new CursorLoader(context, contentUri, projection, selection, selectionArgs, orderBy);
    mCursorLoader.registerListener(LOADER_ID_NETWORK, this);
    mCursorLoader.startLoading();
}

Next, implement OnLoadCompleteListener<Cursor> in your Service to handle load callbacks.

@Override
public void onLoadComplete(Loader<Cursor> loader, Cursor data) {
    // Bind data to UI, etc
}

Lastly, don't forget clean up your Loader when the Service is destroyed.

@Override
public void onDestroy() {

    // Stop the cursor loader
    if (mCursorLoader != null) {
        mCursorLoader.unregisterListener(this);
        mCursorLoader.cancelLoad();
        mCursorLoader.stopLoading();
    }
}
Steven Byle
  • 12,579
  • 4
  • 41
  • 57
  • 1
    that's interesting. Suppose we are somewhere in the middle of executing `onLoadComplete` and the cursor data changes. Will the execution of `onLoadComplete` stop abruptly and start again with the new cursor? I am just trying to understand how to gracefully handle a data refresh while iterating through the cursor in a service. – faizal Jun 29 '14 at 11:36
  • From what I have seen, since `onLoadComplete` is called on the `Service's` main thread, any subsequent call to `onLoadComplete` would simply stack and execute with a new `Cursor` after the initial `onLoadComplete` finishes. This should be almost exactly the same as the behavior you would get with a `LoaderManager` calling `onLoadFinished` from several subsequent data changes. – Steven Byle Jun 30 '14 at 02:04
  • @StevenByle I think you should also call `mCursorLoader.reset()' in order to close cursor. According to source code, 'reset()' will call `onStopLoading();` (which is equal to `stopLoading`) and then will close cursor. I think, otherwise cursor won't be closed. – MyDogTom Oct 28 '15 at 15:10
  • this sorta works but there's no guarantee that the service will complete the request in a reasonable time. – roberto tomás Apr 09 '16 at 21:14
18

Unfortunately, no. Loaders were designed for activities and fragments in order to cleanly handle configuration changes that occur in Activites and Fragments. i.e. Rotating your device and re-attaching to the existing data.

A service does not have any configuration changes, it will sit in the background until it completes or the system is forced to kill it. So assuming you're executing your code on a background thread in your Service (which you should be anyways), theres just no reason to use a Loader. Simply make the calls you need to query your data.

So if your Service is just an IntentService, you can write your logic to query your cursor-backed data in the onHandleIntent() method.

http://developer.android.com/guide/components/loaders.html

kwazi
  • 594
  • 5
  • 8