Несколько погрузчиков с одинаковой активностью

У меня есть два настраиваемых загрузчика, унаследованных от AsyncTaskLoader, которые я хотел бы использовать в своей деятельности. Каждый из них возвращает результат другого типа. Чтобы использовать свою активность для обратного вызова, я должен реализовать два интерфейса:

implements LoaderCallbacks<GetSyncListDataResult>, LoaderCallbacks<ErrorResult>

Однако, пытаясь реализовать требуемые методы в том же классе, я в конечном итоге ошибка повторяющегося метода и ошибка стирания (???):

// 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) ...

Очевидно, что методы сталкиваются, и мне нужен простой способ решить эту проблему. Каким будет правильный способ решения этого вопроса?

Ответ 1

Правильный ответ соответствует комментарию @dymmeh, т.е. не для Activity реализовать два интерфейса LoaderCallbacks, но для того, чтобы активность содержала две реализации LoaderCallbacks. В качестве примера: инициализируйте ваши поля LoaderCallbacks в вашей деятельности...

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

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

... и объявить идентификаторы вашего загрузчика...

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

... и затем инициализируйте ваши загрузчики...

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

... Готово!

Ответ 2

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 ) {

        }
    }
}

Мой пример Github

Ответ 3

На самом деле проще, если вы реализуете LoaderManager.LoaderCallbacks<T> в своем классе Activity и, используя определенные идентификаторы загрузчиков, манипулируете результатом. Таким образом, ваш код станет более читабельным и функциональным (поскольку больше не будет дублирования реализаций интерфейса обратных вызовов внутреннего загрузчика).

Например:

    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() );
    }

Ответ 4

Это необязательно. Внедрение LoaderManager.LoaderCallbacks. Затем, каждый раз, когда вы инициализируете загрузчик, дайте ему уникальный идентификатор. В обратных вызовах вы можете обнаружить идентификатор загрузчика, который вызвал обратный вызов, и предпринять соответствующие действия.

то есть

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: ...
}
...

и т.д.