2013-06-12 15 views
6

Ich habe einen Inhaltsanbieter, einen Content-Resolver und einen Cursor-Loader. Der Loader wird verwendet, um eine Listview indirekt zu füllen (dh kein einfacher Cursor-Adapter, sondern ein Array-Adapter, da ich die Ergebnisse des Cursors verwenden muss, um andere Daten zu sammeln).Cursorloader nicht aktualisiert, wenn sich die zugrunde liegenden Daten ändern

Wenn ich die zugrunde liegenden Daten ändern, wird die Listview nicht ausgefüllt, da der Rückruf onLoadFinished(Loader<Cursor>, Cursor) nicht aufgerufen wird.

Wie vorgeschlagen, während ich dies schreibe, gibt es eine Menge Fragen zu diesem Thema. zB CursorLoader not updating after data change

Und alle Fragen weisen darauf hin, zwei Dinge:

  • In Ihrem Content-Provider-Abfrage() -Methode, müssen Sie a'la den Cursor über Benachrichtigungen sagen

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

  • In Ihrem Content-Provider einfügen/update/delete-Methode müssen Sie n otify auf der URI:

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

ich diese Dinge zu tun.

Ich schließe auch keinen der Cursor, die ich zurückbekomme.

Beachten Sie, dass mein Inhaltsanbieter in einer separaten App lebt (denken Sie daran, dass es sich um eine App für den Inhaltsanbieter handelt - keine Hauptaktivität des Startprogramms). Ein com.example.provider APK, und die com.example.app ruft (im content resolver) über den content: //com.example.provider/table URI etc. auf. Der content resolver (dbhelper) lebt in einem Bibliotheksprojekt (com.example.appdb), mit dem die Aktivität verknüpft wird. (Auf diese Weise können mehrere Projekte den dbhelper via Linking verwenden, und alle Inhaltsanbieter werden über ein einzelnes APK installiert)

Ich habe das Debugging im Loader Manager aktiviert, und kann sehen, wo ich eine Aktualisierung erzwinge, nachdem sich die Daten geändert haben (dh der Loader wird neu gestartet und der vorherige wird als inaktiv markiert), aber nichts, was etwas sagt, passiert automatisch - eher als Reaktion auf meine Force-Aktualisierung.

Irgendwelche Ideen, warum mein Ladeprogramm nicht aktualisiert wird?

- EDIT -

Der Lader erstellen:

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

Wo getFoo() über einen Cursor loader zurückgibt:

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

Loader-Finish führt den Cursor und füllt eine Tabelle (und tut etwas Verarbeitung) - nichts Besonderes dort.

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(); 

Loader Reset löscht die Tabelle.

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(); 

Der Inhaltsanbieter hat:

public Cursor query (Uri uri, String [] Projektion, String Auswahl, String [] selectionArgs, String sortOrder) { Cursor Cursor; SQLiteQueryBuilder qb = neuer 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; 

}

Dann Update einfügen/ähnelt:

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

Das Posten eines Teils Ihres Codes im Zusammenhang mit dem Cursor Loader könnte helfen. Hauptsächlich Ihre Methoden onCreateLoader, onLoaderReset und onLoadFinished. Ich nehme an, dass Ihr ContentProvider den NotifyChange-Aufruf beim Aktualisieren erreicht. – AfzalivE

+0

Sorry, Stürme/Stromausfall usw. hielten mich für einige Zeit fern. –

Antwort

2

Ich sehe, dass Sie nicht swapCursor oder changeCursor in Ihrem onLoadFinished und onLoaderReset anrufen. Dies müssen Sie tun, damit Ihr Adapter auf die Daten zugreifen kann, die in den neuen Cursor geladen wurden.

in onLoadFinished, rufen Sie so etwas wie:

mAdapter.swapCursor(cursor) 

In onLoaderReset, dies nennen Verweise auf den alten Cursor zu entfernen:

mAdapter.swapCursor(null) 

Wo mAdapter Ihre Listview des Adapters ist.

Weitere Informationen: http://developer.android.com/guide/components/loaders.html#onLoadFinished

+0

Ich habe vielleicht das erste Beispiel in meinem Code gewählt, einen, wo es ein Array-Adapter ist, weil wir zusätzliche Informationen suchen müssen, die nicht im Cursor sind, oder in der DB, aus der der Cursor kommt (zB in einer anderen Datenbank). also kann ich kein JOIN in der Abfrage verwenden). Es gibt mehrere andere einfache cursoradapter (oder abgeleitet von einfachen Cursor), die ** 'swapCursor()' auf die zurückgegebenen Daten tun (und auch nicht automatisch aktualisieren). –

+0

Verwenden Sie einen SimpleCursorAdapter und suchen Sie nach weiteren Informationen? Es scheint mir, dass Sie besser einen benutzerdefinierten Adapter verwenden sollten, der diese Additionssuche in der Adapterklasse durchführt. Ich müsste mir die anderen ansehen, die 'swapCursor()' aufrufen, aber nicht aktualisiert werden, da sie ein anderes Problem haben könnten. – AfzalivE

2

Also, für jeden, der das sieht und hat dieses Problem:

Sie sicher, dass die URI Sie den Cursor registrieren Sie sich auf, und die URI benachrichtigt Sie den Cursor auf das sind gleich.

In meinem Fall verwendete ich einen anderen URI zur Abfrage als in anderem Code verwendet wurde, der die zugrunde liegende Tabelle änderte. Es gab keine einfache Lösung, um die Benachrichtigung zu aktivieren. Daher habe ich den Loader in OnResume() als Lösung zurückgesetzt.

1

Dies ist keine direkte Antwort auf dieses spezifische Problem, kann aber anderen in einer ähnlichen Situation helfen. In meinem Fall hatte ich einen Join und obwohl ich den vollen Tabellennamen.Spaltenname in der Projektion und Abfrage verwendet habe. Am Ende verwendete es die falschen ID-Werte. Überprüfen Sie daher Ihren ContentProvider oder Ihre SQL-Syntax.

Verwandte Themen