我通过ContentProvider
将CursorLoader
加载数据工作实现到列表视图中(使用自定义CursorAdapter
)。这是一系列事件。每个项目都有标题,地点等,还有一组优惠,应在每个列表行的LinearLayout
内显示。
问题是Cursor
行只能包含平面数据,而不能包含一组其他项。
我唯一的想法是在数据库上进行加入查询,如下所示:
SELECT * FROM events, offers WHERE events.id=offers.event_id;
但是那时我会有多少行(和列表应该显示事件,所以它不好),列表会过多。也许有可能告诉CursorAdapter
仅使用唯一events.id
填充列表行,但也会以某种方式检索商品数据?
最佳解决方案是在事件Cursor
中放置包含商品的Object
或自定义Cursor
。但是afaik它是不可能的。
答案 0 :(得分:3)
我遇到了同样的问题。事实上,我认为很多人都是。 URI的整个机制 - 通过contentprovider到关系数据库,以及围绕它构建的所有内容(比如各种更改侦听器,文件和流处理) - 这对于非常简单的数据模型来说非常令人印象深刻和有用。
一旦您的应用程序需要更复杂的数据模型,例如 - 表的层次结构,对象关系语义 - 此模型就会中断。 我找到了一堆用于Android的ORM工具,但它们对我来说似乎太“尖锐”了(另外,对于我的生活,我无法弄清楚他们是否有数据更改通知支持)。
ORM今天非常普遍,我真的希望Android用户同意并在平台上添加ORM功能。
这就是我最终做的事情: 游标光标,带有一个前导索引光标,有助于选择正确的内部曲线。 这是一种临时解决方案,我只需继续使用我的代码并稍后再回过头来。希望这可以帮助。 当然,如果您使用listview,您可能还需要创建一个自定义适配器来扩展正确的视图,并进行绑定。
public class MultiCursor implements Cursor {
private final String TAG = this.getClass().getSimpleName();
ArrayList<Cursor> m_cursors = new ArrayList<Cursor>();
Map<Long, CursorRowPair> m_idToCursorRow = Collections.synchronizedMap(new HashMap<Long, CursorRowPair>());
Set<Long> m_idSet = new HashSet<Long>();
Cursor m_idCursor;
/**
* @precondition: _id column must exist on every type of cursor, and has to have index of 0 (be the first)
* @param idCursor
*/
public MultiCursor(Cursor idCursor) {
m_idCursor = idCursor;// this cursor binds the order (1,2,3) to ids
// go over all the ids in id cursor and add to m_idSet
initIdSet();
// m_cursors.add(idCursor);
// m_position = -1;
}
private void initIdSet() {
m_idSet.clear();
long id;
m_idCursor.moveToPosition(-1);
while (m_idCursor.moveToNext()) {
id = m_idCursor.getLong(m_idCursor.getColumnIndex(ContentDescriptor.ShowViewItem.Cols.ID));
m_idSet.add(id);
}
m_idCursor.moveToFirst();
}
public void addCursor(Cursor cursor) {
// when something changes in the child cursor, notify parent on change, to notify subscribers
// cursor.registerContentObserver(new SelfContentObserver(this)); // calls my onchange, which calls the ui
m_cursors.add(cursor);
updateIdToCursorMap(cursor);
}
private class CursorRowPair {
public final Cursor cursor;
public final int row;
public CursorRowPair(Cursor cursor, int row) {
this.cursor = cursor;
this.row = row;
}
}
private void updateIdToCursorMap(Cursor cursor) {
// get object_type
// for each row in cursor, take id, row number
// add id, <cursor,rowNum> to map
long id;
int row = 0;
cursor.moveToPosition(-1);
while (cursor.moveToNext()) {
id = cursor.getLong(cursor.getColumnIndex(ContentDescriptor.ShowViewItem.Cols.ID));
if (m_idSet.contains(id)) m_idToCursorRow.put(id, new CursorRowPair(cursor, row));
row++;
}
cursor.moveToFirst();
}
private Cursor getInternalCursor() {
if (getPosition() < 0 || getCount()==0) return m_idCursor; // todo throw a proper exception
// get the id of the current row
long id = m_idCursor.getLong(m_idCursor.getColumnIndex(ContentDescriptor.BaseCols.ID));
CursorRowPair cursorRowPair = m_idToCursorRow.get(id);
if (null == cursorRowPair) return null;
Cursor cursor = cursorRowPair.cursor;
int row = cursorRowPair.row;
cursor.moveToPosition(row);
return cursor;
}
// //////////////////////////////////////////////
@Override
public void close() {
Log.d(TAG, "close");
for (Cursor cursor : m_cursors) {
cursor.close();
}
m_idCursor.close();
}
@Override
public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
Log.d(TAG, "copyStringToBuffer");
getInternalCursor().copyStringToBuffer(columnIndex, buffer);
}
等等等。
答案 1 :(得分:0)
在您的适配器中查询所有记录的商品光标并使其成为类变量。然后在getView
中使用事件ID迭代商品光标,并在找到合适匹配时将必要的文本视图添加到行布局中。它不优雅,但应该有效。
答案 2 :(得分:0)
不幸的是,一个CursorLoader
只能加载一个Cursor
。因此,解决方案是编写一个自定义AsyncTaskLoader
,返回两个Cursors
。