2012-01-18 18 views
5

Estoy actualizando una aplicación de Android 2.2 para usar CursorLoader (usando la biblioteca de compatibilidad de v4) y me estoy deshojando tratando de entender por qué no se llama al método onLoadFinished cuando el proveedor de contenido notifica un cambio en el contenido asociado con la consulta de CursorLoader.Android CursorLoader no responde a las notificaciones de ContentProvider

El CursorLoader está consultando a un proveedor de contenido del cliente. Mi proveedor establece la notificación URI en su método de consulta:

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

y notifica a los cambios en su insertar/actualizar/borrar métodos:

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

He comprobado que el URI es idéntica en ambos casos. Anteriormente estaba usando ManagedQuery con el mismo proveedor de contenido y el contenido consultado se actualizó correctamente, lo que me hace pensar que el proveedor de contenido probablemente esté bien.

He visto el ejemplo LoaderCursorSupport y, curiosamente, cuando lo ejecuto en mi Nexus One no veo que refleje los cambios que realizo en los nombres de contacto (alternar entre la aplicación de ejemplo y la de contactos). ¿Deberia? Si es así, ¿hay algún problema subyacente del que no tengo conocimiento?

+0

¿Podría proporcionarnos algún código para ayudarnos a identificar el problema? –

+0

Habilitar la depuración podría ayudar, 'LoaderManager.enableDebugLogging (true)' –

+0

Gracias por la sugerencia de depuración. Mi código de cliente es esencialmente el mismo que el ejemplo de LoaderCursorSupport al que hice referencia. Dado que esto presenta el mismo problema, ¿he entendido mal cómo se supone que CursorLoader funciona, es decir, si ejecuto el ejemplo de soporte para mostrar una lista de contactos, edito el contacto en la libreta de direcciones, si no cambia en la lista que muestra el aplicación de ejemplo? – siwatson

Respuesta

-1

Tal vez deberías utilizar contexto de aplicación:

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

Esto no hizo ninguna diferencia, me temo. – siwatson

4

finalmente llegué al fondo de esto y, como suele ser el camino, que era un error estúpido de mi parte. Llamaba cursor.close() en mi método onLoadFinished() - Utilizo el cursor devuelto para crear un ArrayAdapter (necesito insertar manualmente un elemento en la parte superior de la lista) y el cierre del cursor fue un residuo del uso de ManagedQuery antes de migrar para usar CursorLoader.

En el proceso de encontrar esto, creé una clase de prueba simple para mostrar una lista de marcadores y agregar un marcador aleatorio (usando el menú de opciones). Esto funcionó como debería, es decir, se llama a onLoadFinished() después de agregar el elemento. Aquí está el código en caso de que sea útil para cualquier otra persona:

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

Sí. El cursor debe mantenerse activo hasta que se suministre otro en onLoadFinished(). – f470071

Cuestiones relacionadas