并行运行两个AsyncTaskLoader

时间:2014-04-29 10:15:24

标签: android android-fragments android-viewpager loader android-support-library

我正在尝试创建一个搜索功能,将搜索结果加载到片段列表中。问题是搜索会向API发出两个请求:一个用于类型A,另一个用于类型B.

我实现的方法是创建一个包含两个片段FragmentA和FragmentB的ViewPager。每个都通过扩展AsyncTaskLoader的自定义Loader调用API端点和搜索查询,后者执行API查询并返回结果。这是例外;片段接收搜索结果并将其显示在列表中。

我对这种结构唯一的问题是,虽然两个片段都使用单独的LOADER_ID启动它们的加载器,但只有FragmentA实际上从AsyncTaskLoader调用loadInBackground()当我在ViewPager doest中滑动到FragmentB时,它会调用restartLoader()(依次为loadInBackground()),执行搜索的API请求并返回结果。

我想同时运行两个加载器的原因是因为当FragmentB有搜索结果时,ViewPager应该显示FragmentB。

SearchListFragment:

public class SearchListFragment extends Fragment implements LoaderManager.LoaderCallbacks<SearchResults> {

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getLoaderManager().enableDebugLogging(BuildConfig.DEBUG);
        if (mSearchType == SearchType.ARTIST) {
            getLoaderManager().initLoader(R.id.search_artist_loader, null, this);
        } else {
            getLoaderManager().initLoader(R.id.search_track_loader, null, this);
        }
        BusProvider.getInstance().register(this);
    }

    @Override
    public Loader<ApiResponse> onCreateLoader(int id, Bundle args) {
        int offset = 0;
        String query = null;
        if (args != null) {
            if (args.containsKey("offset")) {
                offset = args.getInt("offset");
            }
            if (args.containsKey(SearchManager.QUERY)) {
                query = args.getString(SearchManager.QUERY);
                mSearchQuery = query;
            }
        }
        Log.d(TAG, "onCreateLoader for " + mSearchType.name());
        Log.d(TAG, "id: " + id);

        SearchLoader loader = new SearchLoader(getActivity(), mSearchType, offset, query);
        return loader;
    }

    @Override
    public void onLoadFinished(Loader<SearchResults> loader, SearchResults data) {

        if (data != null) {
            if (data.mSampleList.isEmpty()) {
                mNoResults.setVisibility(View.VISIBLE);
            } else {
                mAdapter.swapApiResponse(data);
                mListView.setVisibility(View.VISIBLE);
            }
            mLoading.setVisibility(View.GONE);
        } else {
            Exception exception = ((SearchLoader) loader).getError();
            if(exception != null) {
                Log.e(TAG, exception.toString());
                Log.e(TAG, exception.getMessage());
                Log.e(TAG, exception.getLocalizedMessage());
            }
            mNoResults.setVisibility(View.VISIBLE);
            mLoading.setVisibility(View.GONE);
        }
    }

    @Override
    public void onLoaderReset(Loader<ApiResponse> loader) {

    }
}

CustomLoader:

public class SearchLoader extends AsyncTaskLoader<ApiResponse> {

    private static final String TAG = SearchLoader.class.getSimpleName();
    private SearchResults mApiResponse;
    private SearchType mSearchType;
    private int mOffset;
    private String mSearchQuery;
    private Exception error = null;

    public SearchLoader(Context context, SearchType type, int offset, String query) {
        super(context);
        mSearchType = type;
        mOffset = offset;
        mSearchQuery = query;
    }

    @Override
    public ApiResponse loadInBackground() {
        try {
            return tryLoadInBackground();
        } catch (Exception e) {

            error = e;
            return null;
        }
    }

    public ApiResponse tryLoadInBackground() throws Exception {
        if (mSearchQuery != null) {
            Map<String, String> parameters = Utils.parametersMap("q:" + mSearchQuery, "offset:" + String.valueOf(mOffset));
            if (mSearchType == SearchType.ARTIST) {
                return API.getRestAdapter().searchTypeA(parameters);
            } else {
                return API.getRestAdapter().searchTypeB(parameters);
            }
        }
        return null;
    }

    @Override
    protected void onStartLoading() {
        Log.d(TAG, "onStartLoading for " + mSearchType.name());
        if (mApiResponse != null) {
            deliverResult(mApiResponse);
        }
        if (takeContentChanged() || mApiResponse == null) {
            forceLoad();
        }
    }


    @Override
    protected void onStopLoading() {
        cancelLoad();
    }

    @Override
    public void onCanceled(ApiResponse data) {
        // Attempt to cancel the current asynchronous load.
        super.onCanceled(data);

        onReleaseResources(data);
    }

    @Override
    protected void onReset() {
        // Ensure the loader has been stopped.
        onStopLoading();


        // At this point we can release the resources associated with 'apps' if needed
        if (mApiResponse != null) {
            onReleaseResources(mApiResponse);
            mApiResponse = null;
        }
    }

    @Override
    public void deliverResult(ApiResponse data) {
        if (isReset()) {
            // An async query came in while the loader is stopped. We don't need the result
            if (data != null) {
                onReleaseResources(data);
            }
            return;
        }
        SearchResults oldData = mApiResponse;
        mApiResponse = data;

        if (isStarted()) {
            // If the loader is currently started, we can immediately deliver a result
            super.deliverResult(mApiResponse);
        }

        // At this point we can release the resources associated with 'oldApps' if needed;
        // now that the new result is delivered we know that it is no longer in use
        if (oldData != null && oldData != mApiResponse) {
            onReleaseResources(oldData);
        }
    }

    /**
     * Helper function to take care of releasing resources associated with an actively loaded data set
     */
    private void onReleaseResources(ApiResponse data) {
        // For a simple list there is nothing to do
        // but for a Cursor we would close it here
    }

    public Exception getError() {
        return error;
    }
}

1 个答案:

答案 0 :(得分:1)