2012-01-18 74 views
5

我正在更新Android 2.2應用程序以使用CursorLoader(使用v4兼容性庫),我正在撕裂我的頭髮,試圖瞭解爲什麼onLoadFinished方法在內容提供者通知與CursorLoader查詢關聯的內容中的更改。Android CursorLoader對ContentProvider通知沒有響應

CursorLoader正在查詢客戶內容提供者。我提供商設置的通知URI在其查詢方法:

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

,並通知其插入/更新更改/刪除方法:

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

我檢查URI是在兩種情況下是相同的。以前,我使用的是帶有相同內容提供者的ManagedQuery,查詢內容更新得很好,這讓我認爲內容提供者可能沒問題。

我看了一下LoaderCursorSupport的例子,有趣的是,當我在Nexus One上運行它時,我沒有看到它反映了我對聯繫人名稱所做的更改(在示例應用程序和聯繫人應用程序之間切換)。應該是?如果是這樣,是否有一些我不知道的潛在問題?

+0

你能提供一些代碼來幫助我們指出問題嗎? – 2012-01-18 23:55:55

+0

啓用調試可能會有所幫助,'LoaderManager.enableDebugLogging(true)' – 2012-01-18 23:58:04

+0

感謝您的調試提示。我的客戶端代碼與我引用的LoaderCursorSupport實例基本相同。鑑於這表現出同樣的問題,我誤解了CursorLoader應該如何工作,即如果我運行支持示例來顯示聯繫人列表,那麼編輯地址簿中的聯繫人,如果它不會在列表中顯示的列表中更改示例應用? – siwatson 2012-01-19 00:07:21

回答

-1

也許你應該使用應用程序上下文:

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

這恐怕沒有什麼區別。 – siwatson 2012-01-19 00:32:57

4

我終於到這條底線,正如通常的方式,這是我的一個愚蠢的錯誤。我在我的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); 
     } 
    } 

} 
+0

是的。遊標應保持活動狀態,直到onLoadFinished()中提供另一遊標爲止。 – f470071 2015-10-02 06:27:27