Android:Cursor.getColumnIndex() 在行循环中是不变的吗?
Android: is Cursor.getColumnIndex() invariant over row loop?
似乎 android.database.Cursor.getColumnIndex(String)
在行循环中应该是不变的。
然而我看到大量代码在做类似的事情:
try (Cursor cursor = database.query(...)) {
while (cursor.moveToNext()) {
String aString = cursor.getString(cursor.getColumnIndex(aColumnName));
// ... other loop code and more repeated use of getColumnIndex()
}
}
除非 getColumnIndex()
的结果真的可以随着对 cursor.moveToNext()
的调用而变化,否则这看起来很愚蠢和浪费——并且这个调用应该像这样被提升到循环之外:
try (Cursor cursor = database.query(...)) {
int aStringIdx = cursor.getColumnIndex(aColumnName);
while (cursor.moveToNext()) {
String aString = cursor.getString(aStringIdx);
// ... other loop code
}
}
或者在最坏的情况下(假设 getColumnIndex()
要求您位于有效数据行上):
try (Cursor cursor = database.query(...)) {
if (cursor.moveToFirst()) {
int aStringIdx = cursor.getColumnIndex(aColumnName);
do {
String aString = cursor.getString(aStringIdx);
// ... other loop code
} while (cursor.moveToNext());
}
}
那么这里的真实故事是什么?
在 getColumnIndex()
和 moveToNext()
方法之间 没有依赖性 。(你的第二个选项将是最好的方法)
您可以通过查看 Cursor interface implementation in AbstractCursor under the moveToPosition() and getColumnIndex() 方法源代码来了解这一点。
I was seeing all did getColumnIndex each time through the row loop, which made no sense at all
可能是因为当我们执行查询时,我们收到一个 SQLiteCursor 实例,而不是 AbstractCursor。如果我们查看源代码,我们会发现内部构建了一个 chache:
@Override
public int getColumnIndex(String columnName) {
// Create mColumnNameMap on demand
if (mColumnNameMap == null) {
String[] columns = mColumns;
int columnCount = columns.length;
HashMap<String, Integer> map = new HashMap<String, Integer>(columnCount, 1);
for (int i = 0; i < columnCount; i++) {
map.put(columns[i], i);
}
mColumnNameMap = map;
}
//...
}
另一方面,访问变量(如您的示例 2)比计算哈希键以获取索引更快。可能相关,具体取决于 table.
的大小
编辑:在具有复杂查询的大型 table 上进行测试,似乎改进接近 5%,在我的情况下不值得进行更改。总的来说,那个HashMap缓存就够用了
似乎 android.database.Cursor.getColumnIndex(String)
在行循环中应该是不变的。
然而我看到大量代码在做类似的事情:
try (Cursor cursor = database.query(...)) {
while (cursor.moveToNext()) {
String aString = cursor.getString(cursor.getColumnIndex(aColumnName));
// ... other loop code and more repeated use of getColumnIndex()
}
}
除非 getColumnIndex()
的结果真的可以随着对 cursor.moveToNext()
的调用而变化,否则这看起来很愚蠢和浪费——并且这个调用应该像这样被提升到循环之外:
try (Cursor cursor = database.query(...)) {
int aStringIdx = cursor.getColumnIndex(aColumnName);
while (cursor.moveToNext()) {
String aString = cursor.getString(aStringIdx);
// ... other loop code
}
}
或者在最坏的情况下(假设 getColumnIndex()
要求您位于有效数据行上):
try (Cursor cursor = database.query(...)) {
if (cursor.moveToFirst()) {
int aStringIdx = cursor.getColumnIndex(aColumnName);
do {
String aString = cursor.getString(aStringIdx);
// ... other loop code
} while (cursor.moveToNext());
}
}
那么这里的真实故事是什么?
在 getColumnIndex()
和 moveToNext()
方法之间 没有依赖性 。(你的第二个选项将是最好的方法)
您可以通过查看 Cursor interface implementation in AbstractCursor under the moveToPosition() and getColumnIndex() 方法源代码来了解这一点。
I was seeing all did getColumnIndex each time through the row loop, which made no sense at all
可能是因为当我们执行查询时,我们收到一个 SQLiteCursor 实例,而不是 AbstractCursor。如果我们查看源代码,我们会发现内部构建了一个 chache:
@Override
public int getColumnIndex(String columnName) {
// Create mColumnNameMap on demand
if (mColumnNameMap == null) {
String[] columns = mColumns;
int columnCount = columns.length;
HashMap<String, Integer> map = new HashMap<String, Integer>(columnCount, 1);
for (int i = 0; i < columnCount; i++) {
map.put(columns[i], i);
}
mColumnNameMap = map;
}
//...
}
另一方面,访问变量(如您的示例 2)比计算哈希键以获取索引更快。可能相关,具体取决于 table.
的大小编辑:在具有复杂查询的大型 table 上进行测试,似乎改进接近 5%,在我的情况下不值得进行更改。总的来说,那个HashMap缓存就够用了