2013-06-12 23 views
6

Ho un provider di contenuti, un risolutore di contenuto e un caricatore di cursori. Il caricatore viene utilizzato per compilare indirettamente un listview (cioè non un semplice adattatore per il cursore, piuttosto un adattatore di array, poiché ho bisogno di usare i risultati del cursore per raccogliere altri dati).Il Cursorloader non si aggiorna quando i dati sottostanti cambiano

Quando cambio i dati sottostanti, la list list non viene popolata non viene richiamata la chiamata onLoadFinished(Loader<Cursor>, Cursor).

Come suggerito mentre sto scrivendo questo, ci sono molte domande su questo problema. esempio CursorLoader not updating after data change

E tutte le domande sottolineano due cose:

  • Nel suo sito web interrogazione fornitore del metodo(), è necessario indicare il cursore sulle notifiche a'la

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

  • Nel metodo di inserimento/aggiornamento/eliminazione del provider di contenuti, è necessario otify sulla URI:

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

sto facendo quelle cose.

Inoltre NON sto chiudendo nessuno dei cursori che torno.

Nota, il mio fornitore di contenuti vive in un'app separata (pensatela come app di content provider - nessuna attività principale di avvio). Un APK com.example.provider e com.example.app sta chiamando (nel resolver del contenuto) tramite il contenuto: //com.example.provider/table URI ecc. Il content resolver (dbhelper) vive in un progetto di libreria (com.example.appdb) in cui l'attività si collega. (In questo modo, più progetti possono utilizzare dbhelper tramite collegamento e tutti i provider di contenuti sono installati tramite APK singolo)

Ho attivato il debug nel gestore di caricamento, e posso vedere dove forzare un aggiornamento dopo che i dati sono cambiati (cioè il riavvio del caricatore e la precedente marcatura inattiva), ma nulla che dice che qualcosa sta accadendo automaticamente - piuttosto, in risposta al mio aggiornamento forzato.

Qualche motivo per cui il mio caricatore non viene aggiornato?

- EDIT -

Il caricatore creare:

Log.d(TAG, "onCreateLoader ID: " + loaderID); 
// typically a switch on the loader ID, and then 
return dbHelper.getfoo() 

Dove getFoo() restituisce un caricatore cursore attraverso:

return new CursorLoader(context, FOO_URI, foo_Fields, foo_query, foo_argArray, foo_sort);

Loader Fine prende il cursore e popola un tavolo (e fa un po 'di elaborazione) - niente di speciale lì.

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 
    Log.d(TAG, "onLoadFinished id: " + loader.getId()); 
    // switch on loader ID .. 
    FillTable(cursor, (FooAdapter) foo_info.listview.getAdapter(); 

Il reset del caricatore cancella la tabella.

public void onLoaderReset(Loader<Cursor> loader) { 
    Log.d(TAG, "onLoaderReset id: " + loader.getId()); 
    // normally a switch on loader ID 
    ((FooAdapter)foo_info.listview.getAdapter()).clear(); 

Il fornitore di contenuti fa:

query del cursore pubblica (Uri uri, String proiezione [], selezione String, selectionArgs String [], String sortorder) { cursore Cursore; SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

SQLiteDatabase db = dbHelper.getReadableDatabase(); 

    switch (sUriMatcher.match(uri)) { 
    case FOO: 
     qb.setTables(FOO); 
     qb.setProjectionMap(FooProjectionMap); 
     break; 
    default: 
     throw new IllegalArgumentException("Unknown URI " + uri); 
    } 

    Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); 

    c.setNotificationUri(getContext().getContentResolver(), uri); 
    return c; 

}

Poi inserimento/aggiornamento è simile:

public Uri insert(Uri uri, ContentValues initialValues) { 
    ContentValues values; 
    if (initialValues != null) { 
     values = new ContentValues(initialValues); 
    } else { 
     values = new ContentValues(); 
    } 

    String tableName; 
    Uri contentUri; 

    switch (sUriMatcher.match(uri)) { 
    case FOO: 
     tableName = FOOTABLE; 
     contentUri = FOO_URI; 
     break; 

    default: 
     throw new IllegalArgumentException("Unknown URI " + uri); 
    } 

    SQLiteDatabase db = dbHelper.getWritableDatabase(); 
    long rowId = db.insert(tableName, null, values); 
    if (rowId > 0) { 
     Uri objUri = ContentUris.withAppendedId(contentUri, rowId); 
     getContext().getContentResolver().notifyChange(objUri, null); 
     return objUri; 
    } 

    throw new SQLException("Failed to insert row into " + uri); 
} 
+0

L'invio di parte del codice correlato al Cursor Loader può essere d'aiuto. Principalmente i tuoi metodi onCreateLoader, onLoaderReset e onLoadFinished. Suppongo che ContentProvider raggiunga la chiamata notifyChange quando si aggiorna. – AfzalivE

+0

Scusa, tempeste/interruzioni di corrente, ecc. Mi hanno tenuto lontano per un po 'di tempo. –

risposta

2

vedo che non sta chiamando swapCursor o changeCursor nel vostro onLoadFinished e onLoaderReset. È necessario farlo per l'adattatore per accedere ai dati caricati nel nuovo cursore.

in onLoadFinished, chiamare qualcosa come:

mAdapter.swapCursor(cursor) 

In onLoaderReset, chiamare questo per rimuovere i riferimenti al vecchio cursore:

mAdapter.swapCursor(null) 

Dove mAdapter è adattatore del ListView.

Maggiori informazioni: http://developer.android.com/guide/components/loaders.html#onLoadFinished

+0

Forse ho scelto il primo esempio nel mio codice, uno in cui è un adattatore di array, perché dobbiamo cercare informazioni aggiuntive che non sono nel cursore, né nel DB dal quale proviene il cursore (cioè è in un database diverso, quindi non posso usare un JOIN nella query). Ci sono molti altri simplecursoradapter (o derivati ​​da un semplice cursore) che ** fanno ** 'swapCursor()' sui dati restituiti (e anche non si autoaggiornano). –

+0

Stai usando un SimpleCursorAdapter e poi stai cercando informazioni aggiuntive? Mi sembra che potresti stare meglio usando un adattatore personalizzato che fa quella ricerca aggiuntiva nella classe dell'adattatore. Dovrei guardare gli altri che chiamano 'swapCursor()' ma non vengono aggiornati perché potrebbero avere qualche altro problema. – AfzalivE

2

Quindi, per chi guarda questo e ha questo problema:

accertarsi che l'URI si registra il cursore, e l'URI notificare il cursore sul sono la stesso.

Nel mio caso, stavo utilizzando un URI diverso per interrogare rispetto a quello utilizzato in altri codici che hanno modificato la tabella sottostante. Non c'era una soluzione semplice per far funzionare la notifica, quindi ho continuato a reimpostare il loader in OnResume() come soluzione.

1

Questa non è una risposta diretta a questo problema specifico, ma può aiutare gli altri in una situazione simile. Nel mio caso, ho avuto un join e anche se ho usato il nome completo tablename.columnname nella proiezione e query. Ha finito per usare comunque i valori ID sbagliati. Assicurati quindi di controllare la sintassi ContentProvider o SQL.

Problemi correlati