Dusan
Dusan

Reputation: 5144

Multiple loaders in same activity

I have two custom built loaders inherited from AsyncTaskLoader which I would like to use in my activity. Each of them returns result of different type. To use my activity for a callback I must implement two interfaces:

implements LoaderCallbacks<GetSyncListDataResult>, LoaderCallbacks<ErrorResult>

However, trying to implement required methods in the same class I end up with duplicate method error and erasure(???) error:

// Methods for the first loader
public Loader<GetSyncListDataResult> onCreateLoader(int ID, Bundle bundle) ...
public void onLoaderReset(Loader<GetSyncListDataResult> loader) ...
public void onLoadFinished(Loader<GetSyncListDataResult> loader, GetSyncListDataResult result) ...

// Methods for the second loader
public Loader<ErrorResult> onCreateLoader(int ID, Bundle bundle) ...
public void onLoaderReset(Loader<ErrorResult> loader) ...
public void onLoadFinished(Loader<ErrorResult> loader, ErrorResult result) ...

Obviously, the methods are clashing and I need an easy way how to resolve this. What would be the proper way of resolving this?

Upvotes: 29

Views: 11869

Answers (4)

dobrivoje
dobrivoje

Reputation: 982

Actually it's simpler if you implement LoaderManager.LoaderCallbacks<T> on your Activity class, and using specific loaders ids, manipulate with result. This way, your code is more readable and functional (because there is no more duplication of interface implementations of inner loader callbacks).

For example :

    public class JobListActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<NetworkResult> {

        public static final  int    SUBMIT_RISK_ASSESSMENT_LOADER = 546;
        public static final  int    LOAD_RISK_ASSESSMENT_LOADER   = 1546;

        public Loader<NetworkResult> onCreateLoader(int id, @Nullable Bundle args) {
            if (id == SUBMIT_RISK_ASSESSMENT_LOADER) {
                return new NetworkLoader( this, args.getString( NetworkLoader.URL_EXTRA ), NetworkLoader.POST, args.getString( BODY ), false ));
            } else if (id == LOAD_RISK_ASSESSMENT_LOADER) {
                return new NetworkLoader( this, args.getString( NetworkLoader.URL_EXTRA ), NetworkLoader.GET, null, false ) );
            }

            return null;
        }

        @Override
        public void onLoadFinished(@NonNull Loader<NetworkResult> loader, NetworkResult data) {
            if (data == null) {
                return;
            }

            Crashlytics.log( Log.INFO, TAG, "onLoadFinished with data [" + data + "]" );

            if (loader.getId() == SUBMIT_RISK_ASSESSMENT_LOADER) {
                    doSemethingElse(data);
            } else if (loader.getId() == LOAD_RISK_ASSESSMENT_LOADER) {
                    doSemethingElse(data);
            }
            LoaderManager.getInstance( this ).destroyLoader( loader.getId() );
    }

Upvotes: 0

Xianwei
Xianwei

Reputation: 2551

class YourActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks {
// you still implements LoaderManager.LoaderCallbacks but without add <returnType> 
//and you have to cast the data into your needed data type in onLoadFinished()

    Private int loader1 = 1;
    private int loader2 =2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_detail);

    getSupportLoaderManager().initLoader(REVIEW_LOADER, null, this);
    getSupportLoaderManager().initLoader(REVIEW_LOADER, null, this);
}
    @Override
    public Loader onCreateLoader(int id, Bundle args) {
        if (id == loader1 ) {

            //YourLoaderClass1 is you loaderClass where you implement onStartLoading and loadingInBackground() 
            return new YourLoaderClass1();  
        } else if (id == loader2 ) {

            return new YourLoaderClass2();
        }
        return null;
    }

    @Override
    public void onLoadFinished(Loader loader, Object data) {
        int id = loader.getId();// find which loader you called
        if (id == loader1 ) {

            yourMethod1((List< >) data); // eg. cast data to List<String>
        } else if (id == loader2 ) {
            yourMethod1((String) data); // eg. cast data to String
        }
    }

    @Override
    public void onLoaderReset(Loader loader) {
        int id = loader.getId();
        if (id == loader1 ) {

        } else if (id == loader2 ) {

        }
    }
}

My Github example

Upvotes: 7

Adil Hussain
Adil Hussain

Reputation: 32113

The correct answer is as per @dymmeh's comment, i.e. not for the Activity to implement two LoaderCallbacks interfaces but for the activity to contain two LoaderCallbacks implementations. By way of example: initialise your LoaderCallbacks fields in your activity...

private LoaderCallbacks<GetSyncListDataResult> dataResultLoaderListener
  = new LoaderCallbacks<GetSyncListDataResult>() { ...methods here... };

private LoaderCallbacks<ErrorResult> errorResultLoaderListener
  = new LoaderCallbacks<ErrorResult>() { ...methods here... };

... and declare your loader ids...

private static final int DATA_RESULT_LOADER_ID = 1;
private static final int ERROR_RESULT_LOADER_ID = 2;

... and then initialise your loaders...

getLoaderManager().initLoader(DATA_RESULT_LOADER_ID, dataResultBundle, dataResultLoaderListener);
getLoaderManager().initLoader(ERROR_RESULT_LOADER_ID, errorResultBundle, errorResultLoaderListener);

... Done!

Upvotes: 52

Joe Malin
Joe Malin

Reputation: 8641

This isn't necessary. Implement LoaderManager.LoaderCallbacks. Then, each time you initialize a loader, give it a unique ID. In the callbacks, you can detect the ID of the loader that caused the callback and take the appropriate action.

that is

class MyLoader extends Activity implements LoaderManager.LoaderCallbacks<GetSyncDataResult> {
...
private static final int LOADER1 = 1;
private static final int LOADER2 = 2;
...
getLoaderManager().initLoader(LOADER1, null, this);
...
getLoaderManager().initLoader(LOADER2, null, this);
...

public Loader<GetSyncDataResult> onCreateLoader(int loaderId, Bundle args) {

    switch (loaderId) {

    case LOADER1: ...
    case LOADER2: ...
}
...

and so forth.

Upvotes: -1

Related Questions