即使应用程序处于非活动状态,CursorLoader如何自动更新视图?

Gop*_*ala 24 android android-loadermanager android-cursorloader

我一直在研究一个小的待办事项列表应用程序.我使用CursorLoader从内容提供者更新ToDolistview.我有一个函数onNewItemAdded(),当用户在文本视图中输入一个新项目并单击Enter时调用该函数.参考下文:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经读过,只要内容提供程序db中有数据更改,CursorLoader就会自动更新视图.这意味着我想,getLoaderManager().restartLoader(0, null, this)只要数据发生变化,就必须隐式调用,对吧?但那并没有发生.每当我添加一个新项目(该项目被添加到数据库中onNewItemAdded,但未明确调用restartLoader)时,请暂停此活动并将其恢复.我没有看到对restartLoader的任何隐式调用(即使db已更改),并且listview也没有更新添加新项目.这是为什么?CursorLoader即使应用程序未处于活动状态,如何自动更新视图?谢谢 :)

编辑:我也用于getContext().getContentResolver().notifyChange(insertedId, null)插入我的内容提供商.

Gop*_*ala 71

我找到了问题的答案.通常,CursorLoader不会自动检测数据更改并将其加载到视图中.我们需要跟踪URI以进行更改.这可以通过以下步骤完成:

  1. 使用以下内容通过游标在内容解析程序中注册Observer :(在ContentProvider的查询方法中完成)
    cursor.setNotificationUri(getContext().getContentResolver(), uri);

  2. 现在,当使用insert()/ delete()/ 对URI基础数据进行任何更改时,update(),我们ContentResolver使用以下方式通知有关更改:

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

  3. 这是由观察者接收到的,我们注册在第1步,这调用ContentResolver.query(),它依次调用ContentProvider的query()方法返回一个新的光标LoaderManager.LoaderManager调用onLoadFinished()传递此游标,以及CursorLoader我们Adapter.swapCursor()用新数据更新View(使用)的位置.

对于Custom AsyncTaskLoaders:

有时我们需要自定义加载器而不是CursorLoader.在这里,我们可以使用除光标之外的其他对象来指向加载的数据(如列表等).在此我们不会通过游标通知ContentResolver.应用程序也可能没有内容提供程序来跟踪URI更改.在这种情况下,我们使用BroadcastReceiver或显式ContentObserver来实现自动视图更新.具体如下:

  1. 我们需要定义我们的自定义加载器,它扩展AsyncTaskLoader并实现其所有抽象方法.与此不同CursorLoader,我们的自定义加载器可能会也可能不会使用内容提供程序,并且ContentResolver.query()当此加载程序被设置时,它的构造函数可能不会调用.所以我们使用广播接收器来达到目的.
  2. 我们需要实例化BroadCastReceiver或ContentObserver以OnStartLoading()抽象的方法AsyncTaskLoader类.
  3. 应该定义此BroadCast接收器以从内容提供者或任何系统事件(如安装的新应用程序)接收数据更改广播,并且必须调用loader的onContentChanged()方法,以通知加载器有关数据更改的信息.Loader会自动完成剩下的工作以加载更新的数据并调用onLoadFinished()以更新视图.

有关详细信息,请参阅:http://developer.android.com/reference/android/content/AsyncTaskLoader.html

我发现这对于明确的解释非常有用:http://www.androiddesignpatterns.com/2012/08/implementing-loaders.html