Uso de CursorLoader sin ContentProvider

La documentación de Android SDK dice que el método startManagingCursor() está depracated:

Este método está obsoleto. Utilice la nueva clase CursorLoader con LoaderManager en su lugar; Esto también está disponible en plataformas más antiguas a través del paquete de compatibilidad de Android. Este método permite que la actividad se encargue de gestionar el ciclo de vida del Cursor dado para usted en función del ciclo de vida de la actividad. Es decir, cuando se detiene la actividad llamará automáticamente a desactivar () en el Cursor dado, y cuando se reinicie más tarde llamará a consulta () para usted. Cuando se destruye la actividad, todos los Cursores administrados se cerrarán automáticamente. Si está apuntando a HONEYCOMB o posterior, considere en su lugar usar LoaderManager en su lugar, disponible a través de getLoaderManager ()

Así que me gustaría usar CursorLoader . ¿Pero cómo puedo utilizarlo con CursorAdapter personalizado y sin ContentProvider , cuando necesito URI en el constructor de CursorLoader ?

Escribí un CursorLoader simple que no necesita un proveedor de contenido:

 import android.content.Context; import android.database.Cursor; import android.support.v4.content.AsyncTaskLoader; /** * Used to write apps that run on platforms prior to Android 3.0. When running * on Android 3.0 or above, this implementation is still used; it does not try * to switch to the framework's implementation. See the framework SDK * documentation for a class overview. * * This was based on the CursorLoader class */ public abstract class SimpleCursorLoader extends AsyncTaskLoader<Cursor> { private Cursor mCursor; public SimpleCursorLoader(Context context) { super(context); } /* Runs on a worker thread */ @Override public abstract Cursor loadInBackground(); /* Runs on the UI thread */ @Override public void deliverResult(Cursor cursor) { if (isReset()) { // An async query came in while the loader is stopped if (cursor != null) { cursor.close(); } return; } Cursor oldCursor = mCursor; mCursor = cursor; if (isStarted()) { super.deliverResult(cursor); } if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) { oldCursor.close(); } } /** * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks * will be called on the UI thread. If a previous load has been completed and is still valid * the result may be passed to the callbacks immediately. * <p/> * Must be called from the UI thread */ @Override protected void onStartLoading() { if (mCursor != null) { deliverResult(mCursor); } if (takeContentChanged() || mCursor == null) { forceLoad(); } } /** * Must be called from the UI thread */ @Override protected void onStopLoading() { // Attempt to cancel the current load task if possible. cancelLoad(); } @Override public void onCanceled(Cursor cursor) { if (cursor != null && !cursor.isClosed()) { cursor.close(); } } @Override protected void onReset() { super.onReset(); // Ensure the loader is stopped onStopLoading(); if (mCursor != null && !mCursor.isClosed()) { mCursor.close(); } mCursor = null; } } 

Sólo necesita la clase AsyncTaskLoader . Ya sea el de Android 3.0 o superior, o el que viene con el paquete de compatibilidad.

También escribí un ListLoader que es compatible con el LoadManager y se utiliza para recuperar una colección genérica de java.util.List .

Escriba su propio cargador que utilice su clase de base de datos en lugar de un proveedor de contenido. La forma más sencilla es simplemente tomar el origen de la clase CursorLoader de la biblioteca de compatibilidad y reemplazar consultas de proveedor con consultas a su propia clase de ayuda de db.

SimpleCursorLoader es una solución simple, sin embargo, no admite la actualización del cargador cuando los datos cambian. CommonsWare tiene una biblioteca loaderex que agrega un SQLiteCursorLoader y admite la re-consulta en los cambios de datos.

https://github.com/commonsguy/cwac-loaderex

Una tercera opción sería simplemente anular loadInBackground :

 public class CustomCursorLoader extends CursorLoader { private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver(); @Override public Cursor loadInBackground() { Cursor cursor = ... // get your cursor from wherever you like if (cursor != null) { // Ensure the cursor window is filled cursor.getCount(); cursor.registerContentObserver(mObserver); } return cursor; } }; 

Esto también se encargará de volver a consultar su cursor cuando cambie la base de datos.

Única advertencia: Tendrás que definir otro observador, ya que Google en su infinita sabiduría decidió hacer su paquete privado. Si usted pone la clase en el mismo paquete que el original (o el compat uno) usted puede utilizar realmente el observador original. El observador es un objeto muy ligero y no se utiliza en ningún otro lugar, por lo que esto no hace mucha diferencia.

La tercera opción propuesta por Timo Ohr, junto con los comentarios de Yeung, proporcionan la respuesta más simple (navaja de Occam). A continuación se muestra un ejemplo de una clase completa que funciona para mí. Hay dos reglas para usar esta clase.

  1. Amplíe esta clase abstracta e implemente los métodos getCursor () y getContentUri ().
  2. Cada vez que cambie la base de datos (por ejemplo, después de insertar o eliminar), asegúrese de llamar

     getContentResolver().notifyChange(myUri, null); 

    Donde myUri es el mismo que regresó de su implementación del método getContentUri ().

Aquí está el código para la clase que usé:

 package com.example.project; import android.content.Context; import android.database.Cursor; import android.content.CursorLoader; import android.content.Loader; public abstract class AbstractCustomCursorLoader extends CursorLoader { private final Loader.ForceLoadContentObserver mObserver = new Loader.ForceLoadContentObserver(); public AbstractCustomCursorLoader(Context context) { super(context); } @Override public Cursor loadInBackground() { Cursor cursor = getCursor(); if (cursor != null) { // Ensure the cursor window is filled cursor.getCount(); cursor.registerContentObserver(mObserver); } cursor.setNotificationUri(getContext().getContentResolver(), getContentUri()); return cursor; } protected abstract Cursor getCursor(); protected abstract Uri getContentUri(); } 
  • EditText en ListView sin reciclar entrada
  • Android: desplazamiento sin fin - ListView y Cursor
  • Android desventajas de no cerrar el cursor
  • Limitación de una consulta SQLite en android
  • Tamaño máximo de Android Cursor
  • ¿Cómo comprobar si un cursor está vacío?
  • Reciclador Ver Agregar Quitar Elemento Animaciones que no se muestran en swapCursor
  • Cómo reemplazar CursorAdapter bindView
  • Consulta SQLite de Android y uso del cursor para tratar varias filas
  • Android: ¿Cómo crear mi propia clase de cursor?
  • Android.database.CursorWindowAllocationException: La asignación de ventana de cursor de 2048 kb falló incluso después de cerrar el cursor
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.