9

I have an activity which uses two Loaders. Each of them returns different type of data. To get data from a single Loader one just implements LoaderCallbacks<D> into an Activity. I guess I could just implement LoaderCallbacks<Object> and check the type of the object and then decide which of the two LoaderCallbacks it is, but it seems like a hack to me (mostly because of the lack of type safety here).

So I thought about making the LoaderCallbacks object a static inner class, something like this:

private static class geocoderLoaderCallbacks implements LoaderCallbacks<List<Address>>{

    @Override
    public Loader<List<Address>> onCreateLoader(int arg0, Bundle arg1) {
        GeocoderTask loader = new GeocoderTask(context, "");
        return loader;
    }

    @Override
    public void onLoadFinished(Loader<List<Address>> loader, List<Address> data) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onLoaderReset(Loader<List<Address>> loader) {
        // TODO Auto-generated method stub

    }


}

And then using lm.initLoader(0, null, geocoderLoaderCallbacks).

Two question arise: is it ok to do, or should I rather stick to implementing LoaderCallbacks into Activity? And how do I safely pass the context into the onCreateLoader? Should I just make a constructor in geocoderLoaderCallbacks and pass the context there like this lm.initLoader(0, null, geocoderLoaderCallbacks(this))?

There is a similar question here LoaderManager with multiple loaders: how to get the right cursorloader but it doesn't explain how to manage two loaders with different data types.

Community
  • 1
  • 1
Michał Klimczak
  • 12,674
  • 8
  • 66
  • 99

1 Answers1

10

It is always ok to move code away from a potentially giant class and it's much cleaner to do it with different classes then with one that can handle everything. You might even want to make them real external classes instead of inner classes if you feel that your Activity has too much code inside. LoaderCallbacks is an interface so you can and mostly should implement it in it's own class.

Passing the Context in the constructor is fine as long as you don't keep static or otherwise cached references to it.

zapl
  • 63,179
  • 10
  • 123
  • 154
  • 1
    I'm not sure if I "keep static or otherwise cached references to it". The context is needed because the AsyncTaskLoader needs one. So I must pass it to the geocoderLoaderCallbacks. But should I instantiate it in my activity and pass reference to this particular activity? Wouldn't it leak the activity? In all example implementations (where Activity implements LoaderCallbacks) they use `lm.initLoader(0, null, this);` (`this`) to pass the reference to activity. Then it's automagically handle by the AsyncTaskLoader. But does it work the same with static inner class? – Michał Klimczak Mar 20 '12 at 13:52
  • 1
    Doing that in a different class and passing the `Context` is safe regarding leaks since you the lifespan of the loader callback class is tied to the lifetime of the activity itself. Once the Activity is garbage collected all references outgoing from there will be too. The only thing that you must not do is to use `static` variables that have some kind of reference to your Activity. You usually won't get problems with leaks if you just use the provided classes as intended. – zapl Mar 20 '12 at 14:06
  • Great, thanks! And +1 for mentioning not to use static variables with reference to Activity – Michał Klimczak Mar 20 '12 at 14:14
  • 1
    Great question/answer. But I'm curious, if you go about making multiple classes that implement `LoaderCallbacks`, doesn't that reduce the usefulness of the `id` parameter? – Gautam Sep 03 '13 at 07:48