Reputation: 5144
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
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
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 ) {
}
}
}
Upvotes: 7
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
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