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
?
- Nullpointerexcepiton en el cursor al seleccionar la foto de la galería en el fragmento de diálogo
- Cursor crashing: Índice 0 solicitado, con un tamaño de 0
- Java.lang.IllegalStateException: No se pudo leer la fila x col x de CursorWindow. Asegúrese de que el Cursor se inicialice correctamente.contacts
- Cómo utilizar la consulta para el argumento de selección múltiple utilizando una columna de selección
- Cursor de cierre en la base de datos SQLite explícitamente, necesarios o no necesarios?
- Cómo obtener una fila específica donde se actualiza el valor en android
- Error de Android: java.lang.IllegalStateException: intentando repetir la consulta de un cursor ya cerrado
- ViewPager PagerAdapter con cursor - CursorLoader.onLoadFinished no se llama con una consulta diferente
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.
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.
- Amplíe esta clase abstracta e implemente los métodos getCursor () y getContentUri ().
-
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(); }
- Mover a otro EditText cuando se hace clic en Soft Keyboard Next en Android
- OnIabPurchaseFinished nunca llamado.