【问题标题】:ListAdapter design adviceListAdapter 设计建议
【发布时间】:2011-01-21 07:43:11
【问题描述】:

我想编写一个 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

如您所见,带有多个标签的便笺将位于结果中的多行上。这意味着我不能看光标大小来确定音符的数量,我需要遍历整个 Cursor 才能得到计数。我不想那样做。

到目前为止,我想出的解决方案是使用两个游标:一个用于上面提到的查询,另一个用于包含 notes 表中行数的查询 (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 的某些部分可以很好地解决这个问题?

提前致谢!

【问题讨论】:

    标签: android listadapter


    【解决方案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 查询如下所示:

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

    您当然可以用当前笔记的任何 id 替换“12”。

    我希望你能利用我的(很长的 :-) 回答。

    【讨论】:

    • 不错的答案。我对 Android 还是很陌生,还没有阅读 ContentProviders。这意味着我不在我当前的代码中使用它们。我只使用了一个基础 SQLiteDatabase,我将它包装在一个名为 NotesDb 的自定义类中。此类返回适配器使用的游标。我认为你关于数据库设计的笔记都是有效的。我想我会全部实施。我需要两个表中的所有信息的原因是我想在 ListView 中显示每个笔记的标签。这就是我认为这一切变得如此复杂的原因。
    • 很高兴我能帮上忙 :-) ContentProviders 的事情也有点尴尬。您实际上并不需要 ContentProvider 来访问您的数据库(您当前的代码就是一个很好的例子)。然而,我发现,当您将数据库“分发”到其他 3:d 方应用程序时,ContentProviders 确实很适合实施。那么遵循“事实上的标准”很好。
    猜你喜欢
    • 2012-10-31
    • 2011-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-28
    • 2010-11-17
    • 2017-08-29
    相关资源
    最近更新 更多