android - 并行运行两个 AsyncTaskLoader

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

我正在尝试创建一个将搜索结果加载到 fragment 列表中的搜索函数。问题是搜索向 API 发出了两个请求:一个针对类型 A,一个针对类型 B。

我的实现方式是创建一个包含两个 fragment 的 ViewPager,FragmentA 和 FragmentB。每个人都通过扩展 AsyncTaskLoader 的自定义加载器调用带有搜索查询的 API 端点,AsyncTaskLoader 执行 API 查询并返回结果。这作为异常(exception)工作; fragment 接收搜索结果并将它们显示在列表中。

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

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

搜索列表 fragment :

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

    }
}

自定义加载器:

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

最佳答案

关于android - 并行运行两个 AsyncTaskLoader,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23361765/

相关文章:

android - 如何在ViewPager中设置OnClickListener

android r.java 不会更新

android - 在 values\attrs.xml 中声明属性时出错

c# - Xamarin C# 安卓 : change color text in a substring?

android - 如何使用多个 NavHost fragment 创建深层链接

android - fragment 应该是静态的,这样它们可以被系统重新实例化,而匿名类不是静态的 [ValidFragment]

android - 我可以控制在 TabLayout/ViewPager 应用程序中何时允许滑动吗?

android - 如何获取屏幕打开的时间

android - 哪个更好 : Loader or Headless Fragments

android - 如何在 zoom android 中应用长按和捏合?