Android ListAdapter-Designhinweise

897
Arlaharen

Ich möchte ein Android-Gerät schreiben ListAdapter, um Daten aus einer Datenbank bereitzustellen, die folgendermaßen aussehen:

CREATE TABLE note (_id integer primary key autoincrement,
                   content text not null)
CREATE TABLE tag (_id integer primary key autoincrement,
                  name text not null);
CREATE TABLE relation (_id integer primary key autoincrement,
                       noteid integer not null,
                       tagid integer not null,
                       idx integer not null);

Ich verwende diese Datenbank, um Notizen und die zugehörigen Tags als geordnete Liste zu speichern. Eine Anforderung des ListAdapter ist, dass der ListView-Inhalt aktualisiert werden muss, wenn sich die zugrunde liegenden Daten ändern. Ich kann mit dieser Abfrage alle Notizen in der Datenbank abfragen:

SELECT note._id AS noteid, 
       note.content, 
       relation.idx AS tagidx,
       tag.name
FROM note
LEFT JOIN relation ON (relation.noteid = note._id)
LEFT JOIN tag ON (tag._id = relation.tagid)
ORDER BY noteid, tagidx;

Dies gibt mir Ergebnisse, die so aussehen (Nullwerte werden zur Verdeutlichung gezeigt)

0|foo bar baz|0|x
1|hello world|null|null
2|one more nn|0|yy
2|one more nn|1|y

Wie Sie sehen, befindet sich eine Notiz mit mehr als einem Tag in mehr als einer Zeile des Ergebnisses. Dies bedeutet, dass ich nicht die Cursorgröße betrachten kann, um die Anzahl der Noten zu bestimmen. Ich muss den gesamten Cursor durchlaufen, um eine Zählung zu erhalten. Das will ich nicht.

Die Lösung, die ich bisher gefunden habe, besteht darin, zwei Cursor zu verwenden: einen mit der oben genannten Abfrage und einen mit einer Abfrage, die die Anzahl der Zeilen in der Notes-Tabelle ( select count(*) from notes) enthält. Im Konstruktor rufe ich an intializeCursors():

private void initializeCursors() {
    notesCursor.moveToFirst();
    countCursor.moveToFirst();
    count = countCursor.getInt(0);
}

Ich habe so umgesetzt getItem():

public Note getItem(int position) {
    // notes is a List of notes that we have already read.
    if (position < notes.size()) { 
        return notes.get(position);
    }

    int cursorPosition = notes.size();
    while (cursorPosition <= position) {
        // Creates a note by reading the correct number of rows.
        Note note = NotesDb.noteFrom(notesCursor); 
        notes.add(note);
        ++cursorPosition;
    }
    return notes.get(position);
}

Der Adapter geht davon aus, dass die Cursor von einigen Benutzern verwaltet werden Activity, die sie aufgerufen startManagingCursor()haben.

So weit so gut, denke ich. Das Problem besteht nun darin, wie mit dem neu zu schreibenden Cursor umzugehen ist . Da ich zwei Cursor habe, muss ich die Hörer für beide registrieren. Wenn ich onChange()sie erhalten habe, kann ich initializeCursors()alle registrierten Hörer ListAdapterüber eine Änderung der Daten informieren .

Das Requery-Szenario ist der eigentliche Grund, warum ich überhaupt zwei Cursor benötigte. Ich habe keine Möglichkeit gefunden, die Anzahl der Noten in einem erforderlichen Cursor zu zählen, anstatt die Datenbank mit einem anderen Cursor abzufragen.

Dies ist das Beste, was ich bisher habe. Ich möchte mit dieser Gruppe die Vernunft dieses Ansatzes überprüfen. :-) Ist diese Zwei-Cursor-Annäherung zu kompliziert? Vielleicht habe ich einen Teil der API verpasst, der dies für mich gut löst?

Antworten
6

1 Antwort auf die Frage

3
vidstige

Ich würde vorschlagen, den eingebauten CursorAdapter zusammen mit einem SQLiteCursor zu verwenden . Sie sollten auch in der Lage sein, Ihre komplexere Abfrage mithilfe des SQLiteQueryBuilder zu erstellen .