Как CursorLoader автоматически обновляет представление, даже если приложение неактивно?

Я работал над небольшим приложением списка дел. Я использовал CursorLoader для обновления ToDolistview у поставщика контента. У меня есть написанная функция onNewItemAdded() , которая вызывается, когда пользователь вводит новый элемент в текстовое представление и нажимает кнопку ввода. См. Ниже:

 public void onNewItemAdded(String newItem) { ContentResolver cr = getContentResolver(); ContentValues values = new ContentValues(); values.put(ToDoContentProvider.KEY_TASK, newItem); cr.insert(ToDoContentProvider.CONTENT_URI, values); // getLoaderManager().restartLoader(0, null, this); // commented for the sake of testing } @Override protected void onResume() { super.onResume(); //getLoaderManager().restartLoader(0, null, this); // commented for the sake of testing } public Loader<Cursor> onCreateLoader(int id, Bundle args) { CursorLoader loader = new CursorLoader(this, ToDoContentProvider.CONTENT_URI, null, null, null, null); Log.e("GOPAL", "In the onCreateLoader"); return loader; } public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { int keyTaskIndex = cursor.getColumnIndexOrThrow(ToDoContentProvider.KEY_TASK); Log.e("GOPAL", "In the onLoadFinished"); todoItems.clear(); if (cursor.moveToNext() == false) Log.e("GOPAL", "Empty Cursor"); else { while (cursor.moveToNext()) { ToDoItem newItem = new ToDoItem(cursor.getString(keyTaskIndex)); todoItems.add(newItem); } aa.notifyDataSetChanged(); // aa is arrayadapter used for the listview } } 

Я прочитал, CursorLoader автоматически обновляет представление, всякий раз, когда происходит изменение данных в db поставщика контента. Это означает, что я предполагаю, getLoaderManager().restartLoader(0, null, this) должен быть вызван неявно всякий раз, когда происходит изменение данных, правильно? Но этого не происходит. Всякий раз, когда я добавляю новый элемент (элемент добавляется в db из onNewItemAdded , но restartLoader явно не вызывается), приостановите это действие и возобновите его. Я не вижу никакого неявного вызова restartLoader (даже если db изменен), и listview также не обновляется с добавленным новым элементом. Почему это? Как CursorLoader автоматически обновляет представление, даже если приложение неактивно ??? Благодаря 🙂

EDIT: Я также использовал getContext().getContentResolver().notifyChange(insertedId, null) во вставке моего поставщика контента.

Solutions Collecting From Web of "Как CursorLoader автоматически обновляет представление, даже если приложение неактивно?"

Я нашел ответ на мой вопрос. В общем случае CursorLoader автоматически не обнаруживает изменения данных и не загружает их для просмотра. Нам нужно отслеживать URI для изменений. Это можно сделать следующими шагами:

  1. Регистрация наблюдателя в разрешении контента с помощью курсора с помощью: (Выполнено в методе запроса ContentProvider)
    cursor.setNotificationUri(getContext().getContentResolver(), uri);

  2. Теперь, когда есть какие-либо изменения в базовых данных URI, используя insert() / delete() / update(), мы уведомляем contentresolver об изменении, используя:

    getContext().getContentResolver().notifyChange(insertedId, null);

  3. Это получено наблюдателем, зарегистрированным на шаге 1, и это вызывает ContentResolver.query() , который вызывает вызов метода Contentent providers query() чтобы вернуть свежий курсор в loaderManager. LoaderManager вызывает onLoadFinished передавая этот курсор вместе с Cursorloader где мы обновляем View (используя adapter.swapcursor() ) со свежими данными.

Для пользовательских AsyncTaskLoaders:

Время от времени нам нужен наш пользовательский загрузчик вместо CursorLoader. Здесь мы можем использовать другой объект, кроме курсора, чтобы указывать на загруженные данные (например, список и т. Д.). В этом случае мы не будем предупреждать ContentResolver с помощью курсора. Приложение может также не иметь провайдера контента, чтобы отслеживать изменения URI. В этом сценарии мы используем BroadcastReceiver или явный ContentObserver для автоматического обновления вида. Это выглядит следующим образом:

  1. Нам нужно определить наш пользовательский загрузчик, который расширяет AsyncTaskLoader и реализует все его абстрактные методы. В отличие от CursorLoader , наш пользовательский загрузчик может использовать или не использовать поставщик содержимого, и его конструктор не может вызывать ContentResolver.query() , когда этот загрузчик установлен. Поэтому мы используем широковещательный приемник для выполнения этой цели.
  2. Нам нужно создать экземпляр BroadCastReceiver или ContentObserver в OnStartLoading() абстрактного класса AsyncTaskLoader .
  3. Этот приемник BroadCast должен быть определен для приема трансляций, изменяющих данные, из поставщика контента или любых системных событий (как и для нового приложения), и он должен вызвать метод onContentChanged() загрузчика, чтобы уведомить загрузчика об изменении данных. Загружатель автоматически делает остальные для загрузки обновленных данных и вызывает onLoadFinished() для обновления представления.

Для получения дополнительной информации см. Это: http://developer.android.com/reference/android/content/AsyncTaskLoader.html

Я нашел это очень полезным для ясного объяснения: http://www.androiddesignpatterns.com/2012/08/implementing-loaders.html

Ну, я думаю, вы можете перезагрузить загрузчик на определенных событиях. Например, в моем случае у меня есть активность TODO. При нажатии кнопки «добавить», он запускает новую активность, которая имеет представление для подачи нового TODO.

Я использую следующий код в родительской активности onActivityResult ()

 getLoaderManager().restartLoader(0, null, this); 

Он отлично работает для меня. Поделитесь, если есть лучший подход.

благодаря
iuq

Получить ссылку на ваш загрузчик при инициализации следующим образом

  Loader dayWeatherLoader = getLoaderManager().initLoader(LOADER_DAY_WEATHER, null, this); 

Затем создайте класс, который расширяет ContentObserver следующим образом

  class DataObserver extends ContentObserver { public DataObserver(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange, Uri uri) { dayWeatherLoader.forceLoad(); } } 

Затем зарегистрируйте наблюдателя содержимого внутри метода жизненного цикла onResume следующим образом

 @Override public void onResume() { super.onResume(); getContext().getContentResolver().registerContentObserver(CONTENTPROVIDERURI,true,new DayWeatherDataObserver(new Handler())); } 

Всякий раз, когда происходит изменение базовых данных поставщика контента, вызывается метод onChange contentobserver, где вы можете попросить загрузчика снова загрузить данные