Uso de CursorLoader sin ContentProvider


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

Este método está obsoleto. Utilice la nueva clase CursorLoader con LoaderManager; 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 administrar el ciclo de vida del Cursor en función del ciclo de vida de la actividad. Es decir, cuando la actividad se detiene automáticamente llamará a deactivate() en el Cursor dado, y cuando se reinicie más tarde, llamará a requery () por usted. Cuando se destruye la actividad, todos los cursores administrados se cerrarán automáticamente. Si está apuntando a HONEYCOMB o posterior, considere usar LoaderManager en su lugar, disponible a través de getLoaderManager()

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

Author: sealskej, 2011-08-25

5 answers

Escribí un simple CursorLoader 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;
    }
}

Solo necesita la clase AsyncTaskLoader. Tanto en Android 3.0 o superior, o el que viene con el paquete de compatibilidad.

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

 153
Author: Cristian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-22 18:38:02

Escriba su propio cargador que use su clase de base de datos en lugar de un proveedor de contenido. La forma más fácil es simplemente tomar el origen de la clase CursorLoader de la biblioteca de compatibilidad, y reemplazar las consultas del proveedor con consultas a su propia clase auxiliar de base de datos.

 22
Author: Nikolay Elenkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-25 02:54:07

El 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

 14
Author: emmby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-22 17:58:51

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 el cursor cuando la base de datos cambie.

Solo advertencia: Usted tendrá que definir otro observador, ya que Google en su infinita sabiduría decidió hacer su paquete privado. Si pones la clase en el mismo paquete que la original (o la compat) puedes usar 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.

 12
Author: Timo Ohr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-28 18:24:11

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. Extienda esta clase abstracta e implemente los métodos getCursor() y getContentUri().
  2. Cada vez que cambie la base de datos subyacente (por ejemplo, después de insertar o eliminar), asegúrese de llamar a

    getContentResolver().notifyChange(myUri, null);
    

    Donde myUri es el mismo devuelto desde 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();
  }
 2
Author: John Moore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-04 23:20:36