Сообщите Android AsyncTaskLoader, чтобы получить больше данных

Позвольте мне начать, сказав, что это НЕ вопрос о прокрутке ListViews. Я не хочу знать, как сказать, когда пользователь прокручивается до нижней части списка, поэтому, пожалуйста, не давайте мне ответов на этот вопрос или не отмечайте это как дубликат.

Я использую класс, который расширяет AsyncTaskLoader, чтобы заполнить ListView данными из веб-службы.

Первоначально я загружаю 50 предметов, и все работает отлично. Мне нужно знать, как заставить Loader загружать следующие 50 элементов пошагово. Я понимаю WHERE, чтобы сделать это в коде ListView, но я не могу понять, как лучше сказать загрузчику, что я хочу загрузить больше данных, не перезагружая его и не загружая все снова.

Опять же, чтобы уточнить, проблема, которую я пытаюсь решить здесь, просто уведомляет загрузчика о необходимости загрузки большего количества данных. Он уже знает, как загружать больше данных, когда loadInBackground () вызывается во второй раз, и ListView уже знает, где / когда нужно уведомить загрузчика, вопрос в том, как это сделать .

Некоторые из соответствующих кода:

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

Я все еще хотел бы знать, является ли это способом «наилучшей практики», но, похоже, сейчас это решает мою проблему.

В вашем сценарии я рекомендую вам использовать 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); 

Даже когда активность, удерживающая загрузчик, находится в фоновом режиме или невозможна доставкаResult. И вам не нужны экземпляры погрузчиков.

Все уведомления вокруг Uri объекта. Uri является мощным представлением данных в Android.

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