【问题标题】:Android CursorLoader not responding to ContentProvider notificationsAndroid CursorLoader 没有响应 ContentProvider 通知
【发布时间】:2012-01-18 23:41:55
【问题描述】:

我正在更新一个 Android 2.2 应用程序以使用 CursorLoader(使用 v4 兼容性库),并且我正在努力理解为什么当内容提供者通知更改时不调用 onLoadFinished 方法与 CursorLoader 查询关联的内容。

CursorLoader 正在查询客户内容提供商。我的提供者在其查询方法中设置了通知 URI:

cursor.setNotificationUri(getContext().getContentResolver(), uri);

并通知其插入/更新/删除方法的更改:

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

我检查了这两种情况下的 URI 是否相同。以前我使用的是具有相同内容提供者的 ManagedQuery,并且查询的内容更新得很好,这让我认为内容提供者可能没问题。

我查看了 LoaderCursorSupport 示例,有趣的是,当我在 Nexus One 上运行它时,我没有看到它反映了我对联系人姓名所做的更改(在示例应用程序和联系人应用程序之间切换)。应该是?如果是这样,是否存在一些我不知道的潜在问题?

【问题讨论】:

  • 您能提供一些代码来帮助我们查明问题吗?
  • 启用调试可能会有所帮助,LoaderManager.enableDebugLogging(true)
  • 感谢调试提示。我的客户端代码与我引用的 LoaderCursorSupport 示例基本相同。鉴于这表现出同样的问题,我是否误解了 CursorLoader 应该如何工作,即如果我运行支持示例以显示联系人列表,然后编辑地址簿中的联系人,如果它不会在显示的列表中更改示例应用?
  • 我没有管理游标。根据示例,我正在 onCreateLoader 中创建一个 Loader 。什么是 initLoader()?
  • 所以让我正确理解这一点...您是要更改当前显示的数据(即更改正在显示的联系人的姓名),还是要显示一组不同的数据(即您想执行另一个查询并显示该数据?)

标签: android android-contentprovider android-cursorloader


【解决方案1】:

我终于明白了这一点,而且通常情况下,这对我来说是一个愚蠢的错误。我在 onLoadFinished() 方法中调用 cursor.close() - 我使用返回的光标创建一个 ArrayAdapter (我需要在列表顶部手动插入一个项目),并且光标关闭是使用 ManagedQuery 的遗留物在迁移到使用 CursorLoader 之前。

在找到这个的过程中,我创建了一个简单的测试类来显示书签列表并添加一个随机书签(使用选项菜单)。这可以正常工作,即在添加项目后调用 onLoadFinished() 。这是代码,以防它对其他人有用:

package com.test;

import android.content.ContentValues;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Browser;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SimpleCursorAdapter;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

public class CursorLoaderTestActivity extends FragmentActivity 
{
    private static final String TAG = CursorLoaderTestActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        FragmentManager fm = getSupportFragmentManager();

        // Create the list fragment and add it as our sole content.
        if (fm.findFragmentById(android.R.id.content) == null) 
        {
            CursorLoaderListFragment list = new CursorLoaderListFragment();
            fm.beginTransaction().add(android.R.id.content, list).commit();
        }
    }


    public static class CursorLoaderListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> 
    {

        // This is the Adapter being used to display the list's data.
        SimpleCursorAdapter mAdapter;

        // If non-null, this is the current filter the user has provided.
        String mCurFilter;

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

            // Give some text to display if there is no data.  In a real
            // application this would come from a resource.
            setEmptyText("No data");

            // We have a menu item to show in action bar.
            setHasOptionsMenu(true);

            // Create an empty adapter we will use to display the loaded data.
            mAdapter = new SimpleCursorAdapter(getActivity(),
                    android.R.layout.simple_list_item_1, null,
                    new String[] { Browser.BookmarkColumns.TITLE },
                    new int[] { android.R.id.text1}, 0);

            setListAdapter(mAdapter);

            // Start out with a progress indicator.
            setListShown(false);

            // Prepare the loader.  Either re-connect with an existing one,
            // or start a new one.
            getLoaderManager().initLoader(0, null, this);
        }

        //@Override 
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) 
        {
            // Place an action bar item for searching.
            MenuItem item = menu.add("Add Item");
            //item.setIcon(android.R.drawable.ic_menu_search);
            MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
        }

        @Override
        public boolean onOptionsItemSelected (MenuItem item)
        {
            ContentValues cv=new ContentValues();
            cv.put(Browser.BookmarkColumns.TITLE, "!AA " + System.currentTimeMillis());
            cv.put(Browser.BookmarkColumns.URL, "http://test/");
            cv.put(Browser.BookmarkColumns.BOOKMARK, 1);
            getActivity().getContentResolver().insert(Browser.BOOKMARKS_URI, cv);
            return true;
        }

       //columns to query
        static final String[] PROJECTION = new String[] { Browser.BookmarkColumns.TITLE };


        public Loader<Cursor> onCreateLoader(int id, Bundle args) 
        {
            Log.i(TAG, "onCreateLoader");

            return new CursorLoader(getActivity(), Browser.BOOKMARKS_URI,
                    PROJECTION, null, null,
                    Browser.BookmarkColumns.TITLE + " ASC");
        }

        public void onLoadFinished(Loader<Cursor> loader, Cursor data) 
        {
            Log.i(TAG, "onLoadFinished");

            // Swap the new cursor in.  (The framework will take care of closing the
            // old cursor once we return.)
            mAdapter.swapCursor(data);

            // The list should now be shown.
            if (isResumed()) 
                setListShown(true);
            else 
                setListShownNoAnimation(true);
        }

        public void onLoaderReset(Loader<Cursor> loader) 
        {
            // This is called when the last Cursor provided to onLoadFinished()
            // above is about to be closed.  We need to make sure we are no
            // longer using it.
            mAdapter.swapCursor(null);
        }
    }

}

【讨论】:

  • 是的。光标应该保持活动状态,直到在 onLoadFinished() 中提供另一个光标。
【解决方案2】:

也许你应该使用应用程序上下文:

getContext().getApplicationContext().getContentResolver().notifyChange(uri, null);

【讨论】:

  • 恐怕这并没有什么不同。
猜你喜欢
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 2017-02-11
  • 1970-01-01
  • 1970-01-01
  • 2013-03-16
  • 1970-01-01
  • 2012-10-03
相关资源
最近更新 更多