2011-01-21 179 views
0

我想寫一個ListAdapter從看起來像這樣的數據庫提供數據:ListAdapter設計建議

CREATE TABLE notes (_id integer primary key, 
        content text); 
CREATE TABLE tags (_id integer primary key, 
        name text, 
        pos integer 
        noteid integer, 
        foreign key(noteid) references notes(_id)); 

我使用這個數據庫來存儲筆記和它們相關的標籤。 ListAdapter的一個要求是它必須能夠在基礎數據更改時更新ListView內容。我可以查詢所有的筆記在數據庫中與此查詢:

select notes._id as id, notes.content, tags.pos, tags.name 
    from notes left join tags on id = tags.noteid 
    order by id, tags.pos; 

哪位能給我的結果看起來像這樣(爲清楚起見,顯示爲空值):

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

正如你所看到的,記在結果中多於一行的標籤將位於多行中。這意味着我不能查看光標大小來確定筆記的數量,我需要遍歷整個光標以獲得計數。我不想這樣做。

我到目前爲止所提出的解決方案是使用兩個遊標:一個用上面提到的查詢,另一個用包含筆記表(select count(*) from notes)中的行數的查詢。在構造函數中我稱之爲intializeCursors()

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

我已經實現的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); 
} 

適配器假定遊標被一些的活動,呼籲他們startManagingCursor()管理。

到目前爲止這麼好,我猜。現在的問題是如何處理被重新查詢的光標。由於我有兩個遊標,因此我需要爲它們註冊偵聽器,並且當我收到它們兩個的onChange()時,我可以initializeCursors(),並通知任何註冊到我的ListAdapter的偵聽器的數據更改。

這是迄今爲止我所見過的最好的。我想用這個小組來檢查這種方法的完整性。 :-)這樣複雜嗎?也許我錯過了爲我解決這個問題的API的一部分?

在此先感謝!

回答

1

根據您的ContentProvider實現方式,如果您選擇擴展CursorAdapter而不是ListAdapter,則可以自動爲您處理此功能。

如果,在你的ContentProvider,調用是這樣的:

getContext().getContentResolver().notifyChange(uri, myObserver); 
只要更改

東西(插入,刪除,更新),然後(根據上的文檔 '有NotifyChange()' 函數:http://developer.android.com/reference/android/content/ContentResolver.html )CursorAdapters默認會得到這個通知。最後,我會帶你對你的數據庫結構發表評論的自由(請不要覺得不高興,我不是故意粗魯,我只是想幫忙)。

注#1 許多數據庫架構師都聲稱,以單數形式命名錶是「事實上的標準」,因此,如果兩張表被命名爲「note」和「tag」,那麼您的兩張表可能會更專業一些。

備註#2 它也似乎有你的筆記和標籤(一個筆記可以有很多標籤,但一個標籤也可以屬於許多筆記)之間的多對多關係。爲避免「標籤」表中出現重複數據,最好將「筆記」和「標籤」完全相互分開,並引入第三個表格,比如說「關係」,它將描述你的筆記和你的標籤。然後,您將有三個表,如:

CREATE TABLE note (_id INTEGER PRIMARY KEY, 
        content TEXT); 

CREATE TABLE tag (_id INTEGER PRIMARY KEY, 
        name TEXT, 
        pos INTEGER); 

CREATE TABLE relation (_id INTEGER PRIMARY KEY, 
         note_id INTEGER, 
         tag_id INTEGER); 

這個架構的變化會增加複雜性的數據庫,但它也將使其更加容錯(尤其是改變),更快一些觀點(該數據庫將不再需要在過濾查詢時測試所有這些重複項),並且節省空間。隨着數據庫的增長,這些「新功能」變得更加有趣。

一個典型的SELECT查詢,一切被選中,那麼會是這個樣子:

SELECT note._id AS noteid, note.text, tag.name, tag.pos FROM note 
LEFT JOIN relation ON (relation.note_id = note._id) 
LEFT JOIN tag ON (tag._id = relation.tag_id); 

注3: 這使我想起我的最後一點。我真的不知道你的應用程序是什麼樣子的,所以我可能在這裏錯了,但是:你是否真的需要從兩個表中獲得所有信息(當前是「註釋」和「標籤」)?只有在編輯或查看單個音符時纔可以單獨獲取所有「音符」,並將其顯示在某種列表或其他GUI星座中,並獲取相應的標記?這樣你會擺脫你的額外「數」光標。

選擇查詢獲取屬於給定記下所有的標籤將是這個樣子:

SELECT tag.* FROM relation 
LEFT JOIN tag ON (tag._id = relation.tag_id) 
WHERE relation.note_id=12; 

你當然會與任何ID當前音符都有取代「12」。

我希望你能使用我的(很長:-)答案。

+0

不錯的答案。我對Android非常陌生,但我還沒有閱讀ContentProviders。這意味着我不會在我當前的代碼中使用它們。我只是使用一個基本的SQLiteDatabase,我已經包裝在一個名爲NotesDb的自定義類中。該類返回適配器使用的遊標。 關於數據庫設計的注意事項我認爲都是有效的。我想我會全部實現它們。 我需要這兩個表中的所有信息的原因是我想要在ListView中顯示每個音符的標籤。這就是爲什麼這一切都變得如此複雜,我認爲。 – Arlaharen 2011-01-21 17:41:59