让我先说这不是一个关于滚动ListViews的问题。我不想知道当用户滚动到列表底部时如何判断,所以请不要给我这个问题的答案,或者将此标记为重复。
我正在使用一个类扩展AsyncTaskLoader填充ListView与数据从web服务。
最初,我加载了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;
}
我想出了一个可行的方法。在我的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();
// ...
}
}
我仍然想知道这是否是"最佳实践"的方式,但它似乎解决了我现在的问题。
在你的场景中,我建议你使用forceloadcontenttobserver,你可以用一个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);
即使持有加载器的活动在后台或无法交付result。你不需要获取loader的实例。
所有的通知都围绕对象的Uri。Uri在Android中是一种强大的数据表示。
但我也有我的困惑。在这个场景中,您的方法和我的方法都假设——内容更改意味着加载更多的数据。但如果确实需要重新加载所有数据该怎么办?您将使用哪种通知?