6

首先让我说这不是关于滚动 ListViews 的问题。我不想知道如何判断用户何时滚动到列表底部,因此请不要给我该问题的答案,或将其标记为重复。

我正在使用扩展 AsyncTaskLoader 的类来使用来自 Web 服务的数据填充 ListView。

最初,我加载了 50 个项目,一切正常。我需要知道如何告诉加载器以增量方式加载接下来的 50 个项目。我了解在 ListView 代码中执行此操作的位置,但我想不出告诉加载程序我想加载更多数据而不重置它并再次加载所有内容的最佳方法。

再次澄清一下,我在这里要解决的问题只是通知加载程序需要加载更多数据。它已经知道在第二次调用 loadInBackground() 时如何加载更多数据,并且 ListView 已经知道在何处/何时通知 Loader,问题是如何

一些相关代码:

@Override
public void onActivityCreated(Bundle savedInstanceState)
{
    super.onActivityCreated(savedInstanceState);

    m_adapter = new SearchAdapter(getActivity());
    setListAdapter(m_adapter);

    // if the loader doesn't already exist, one will be created
    // otherwise the existing loader is reused so we don't have
    // to worry about orientation and other configuration changes
    getLoaderManager().initLoader(SEARCH_LOADER_ID, null, this);
}

@Override
public Loader<List<Result>> onCreateLoader(int id, Bundle args)
{
    String query = args != null ? args.getString(QUERY_KEY) : "";
    return new SearchLoader(getActivity(), query);
}

private class SearchAdapter extends ArrayAdapter<Result>
{
    // ...

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {

        // ...

        if (position == getCount() - 2)
            // TODO: Need to notify Loader here

        // ...
    }
}

private static class SearchLoader extends OurAsyncTaskLoader<List<Result>>
{
    public SearchLoader(Context context, String query)
    {
        super(context);

        m_query = query;
        m_data = Lists.newArrayList();
        m_loadedAllResults = false;
    }

    @Override
    public List<Result> loadInBackground()
    {
        if (m_loadedAllResults)
            return m_data;

        // the Loader implementation does a == check rather than a .equals() check
        // on the data, so we need this to be a new List so that it will know we have
        // new data
        m_data = Lists.newArrayList(m_data);

        MyWebService service = new MyWebService();
        List<Result> results = service.getResults(m_query, m_data.size(), COUNT);
        service.close();

        if (results == null)
            return null;

        if (results.size() < COUNT)
            m_loadedAllResults = true;

        for (Result result : results)
            m_data.add(result)

        return m_data;
    }

    private static final int COUNT = 50;

    private final String m_query;

    private boolean m_loadedAllResults;
    private List<Result> m_data;
}
4

2 回答 2

3

我想出了一个可行的方法。在我的SearchAdapter#getView()方法中,我有以下代码:

private class SearchAdapter extends ArrayAdapter<Result>
{
    // ...

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {

        // ...

        if (position == getCount() - 2)
            getLoaderManager().getLoader(SEARCH_LOADER_ID).onContentChanged();
        // ...
    }
}

我仍然想知道这是否是“最佳实践”的方式,但它现在似乎解决了我的问题。

于 2013-06-06T18:52:09.767 回答
0

在您的场景中,我建议您使用 ForceLoadContentObserver,您可以将其与 URI 绑定到 ContentResolver。像这样:

class SearchLoader ....
     ForceLoadContentObserver contentObserver = new ForceLoadContentObserver();
     ....

     @Override
     public void onStartLoading() {
        if (cacheResult == null || takeContentChanged()) { // This will see if there's a change notification to observer and take it.
            onForceLoad();
        } else {
            deliverResult(cacheResult);
        }
     }

     @Override
     public Result loadInBackground() {
        Result result = loadResult();
        // notification uri built upon Result.BASE_URI so it receives all notifications to BASE_URI.
       getContext().getContentResolver().registerContentObserver(result.getNotificationUri(), true, contentObserver);
     }

     @Override
     public void onReset() {
        // ... Do your clean stuff...
        getContext().getContentResolver().unregisterContentObserver(contentObserver);
     }

     ...
}

因此,您可以使用以下命令在任何地方通知您的更改:

context.getContentResolver().notifyChanged(Result.BASE_URI, null);

即使持有加载器的活动在后台或无法传递结果。而且您不需要获取加载程序的实例。

所有通知都围绕对象的 Uri。Uri 是 Android 中数据的强大表示。

但我也有我的困惑。在这种情况下,您的方法和我的方法都假定 内容更改意味着加载更多数据。但是,如果您确实需要重新加载所有数据怎么办?您将使用什么样的通知?

于 2014-09-10T09:35:40.733 回答