update studio query objeto movetofirst cursores android database sqlite android-contentresolver

android - studio - registerContentObserver() en el cursor de SQLite sin procesar



sqlite where android (2)

Esto es realmente posible.

Tienes que definir un Uri en algún lugar (tal vez una constante).

Yo aconsejaría usar algo como esto:

public static final Uri URI_MY_TABLE = Uri.parse("sqlite://com.example.<your-app-package>/table");

Luego, cuando actualices los datos de la base de datos que llamas:

context.getContentResolver().notifyChange(Constants.URI_MY_TABLE, null);

Y desde el CursorLoader que estás escribiendo, haz algo como:

final ForceLoadContentObserver observer; public MyCursorLoader(final Context context, ...) { super(context); // ... this.observer = new ForceLoadContentObserver(); } @Override public Cursor loadInBackground() { SQLiteDatabase db = this.dbHelper.getReadableDatabase(); final Cursor c = queryDatabase(db); if (c != null) { // Ensure the cursor window is filled c.getCount(); // this is to force a reload when the content change c.registerContentObserver(this.observer); // this make sure this loader will be notified when // a notifyChange is called on the URI_MY_TABLE c.setNotificationUri(getContext().getContentResolver(), Constants.URI_MY_TABLE); } return c; }

ForceLoadContentObserver es una clase interna estática pública dentro de la clase Loader . Si está utilizando la biblioteca de soporte, será android.support.v4.content.Loader.ForceLoadContentObserver.

En el mismo cargador, asegúrese de forzar la carga si los datos cambian:

@Override protected void onStartLoading() { if (this.cursor != null) { deliverResult(this.cursor); } // this takeContentChanged() is important! if (takeContentChanged() || this.cursor == null) { forceLoad(); } }

Un buen comienzo para su CursorLoader si no sabe cómo escribirlo es este: Uso del CursorLoader sin ContentProvider

Tu CursorAdapter ahora debería inicializarse así:

public MyCursorAdapter(Context context, Cursor c) { super(context, c, 0); }

ContentResolver se encargará de notificar al observador en el uri que configuró.

Así es exactamente cómo funciona el ContentProvider .

Si no está utilizando un cargador , puede hacer lo mismo, las modificaciones importantes son:

  • Llame a ContentResolver.notifyChange (URI, null); cuando cambias los datos
  • Call Cursor.setNotificationUri (ContentResolver, URI); cuando carga el cursor

De esta manera, cuando registre un observador, se le notificará cuando cambien los datos subyacentes.

Todos los ejemplos que he visto sobre el uso de registerContentObserver() lo hacen a través de una interfaz ContentProvider . Pero el Cursor tiene una llamada a registerContentObserver() , así que pensé que tal vez la gente de Android ha armado un poco de magia profunda que permitiría obtener actualizaciones en un cursor SQLite cuando una de las filas de un conjunto de resultados activo cambiara. O lo estoy haciendo mal, o no hay tal magia. Aquí está el código con el que estoy trabajando, con la expectativa de que cuando haga clic en el botón para actualizar el valor en la fila # 1 obtendría una devolución de llamada onChange() . ¿Algunas ideas?

public class MainActivity extends Activity { private static final String DATABASE_NAME = "test.db"; public static final String TAG = "dbtest"; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button make = (Button)findViewById(R.id.btn_make_record); make.setOnClickListener(new OnClickListener() { public void onClick(View v) { MyOpenHelper oh = new MyOpenHelper(v.getContext()); SQLiteDatabase wdb = oh.getWritableDatabase(); ContentValues cv = new ContentValues(); cv.put("value", String.valueOf(System.currentTimeMillis())); if (wdb.insert(MyOpenHelper.TABLE_NAME, null, cv) == -1) { Log.d(TAG, "Unable to insert row"); } else { Log.d(TAG, "Inserted row "); } wdb.close(); } }); Button update = (Button)findViewById(R.id.btn_update_record); update.setOnClickListener(new OnClickListener() { public void onClick(View v) { MyOpenHelper oh = new MyOpenHelper(v.getContext()); SQLiteDatabase wdb = oh.getWritableDatabase(); ContentValues cv = new ContentValues(); cv.put("value", String.valueOf(System.currentTimeMillis())); int count = wdb.update(MyOpenHelper.TABLE_NAME, cv, "_id = ?", new String[] {"1"}); Log.d(TAG, "Updated " + count + " row(s)"); wdb.close(); } }); MyOpenHelper oh = new MyOpenHelper(this); SQLiteDatabase rdb = oh.getReadableDatabase(); Cursor c = rdb.query(MyOpenHelper.TABLE_NAME, null, "_id = ?", new String[] {"1"}, null, null, null); startManagingCursor(c); contentObserver = new MyContentObserver(new Handler()); c.registerContentObserver(contentObserver); } private class MyContentObserver extends ContentObserver { MyContentObserver(Handler handler) { super(handler); } public boolean deliverSelfNotifications() { return true; } public void onChange(boolean selfChange) { super.onChange(selfChange); Log.d(TAG, "Saw a change in row # 1"); } } MyContentObserver contentObserver; public class MyOpenHelper extends SQLiteOpenHelper { private static final int DATABASE_VERSION = 1; private static final String TABLE_NAME = "test"; private static final String TABLE_CREATE = "CREATE TABLE " + TABLE_NAME + " (" + "_id INTEGER PRIMARY KEY AUTOINCREMENT," + "value TEXT);"; MyOpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(TABLE_CREATE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub } } }


No tomadores ¿eh? Bueno, una excelente excusa para profundizar en mí mismo y resolverlo. Para aquellos que tengan curiosidad después de mí, si descarga la fuente de la plataforma, los archivos relevantes para ver son:

frameworks / base / core / java / android / database / sqlite / SQLiteCursor.java frameworks / base / core / java / android / database / AbstractCursor.java

Parece que mContentObservable está allí para señalar diferentes partes de un programa que se ejecuta fuera del conjunto de resultados en caché en un Cursor, y el observable es una señal del conjunto de resultados en caché para que los consumidores sepan cuándo se ha volcado / actualizado la caché. No se vincula con la implementación de SQLite para desencadenar eventos cuando se manipula el almacén de datos subyacente.

No es exactamente sorprendente, pero dada la documentación, pensé que tal vez me estaba perdiendo algo.