Android:如何创建我自己的光标类?

发布于 2024-11-01 08:38:23 字数 743 浏览 1 评论 0原文

我在 Android 中使用 Sqlite 并从数据库中获取值,我使用这样的方法:

Cursor cursor = sqliteDatabase.rawQuery("select title,category from table", null);

int columnIndexTitle = cursor.getColumnIndex("title");
iny columnIndexCategory = cursor.getColumnIndex("category");

cursor.moveToFirst();
while (cursor.moveToNext()) {
    String title = cursor.getString(columnIndexTitle);  
    String category = cursor.getString(columnIndexCategory);    
}
cursor.close();

我想创建自己的游标,以便我可以执行 getColumnIndex()getString() 用一种方法。像这样的事情:

String title = cursor.getString("title");

我想创建自己的类来扩展从 sqliteDatabase.rawQuery 获得的游标,但我不确定如何实现这一点。我应该扩展 SQLiteCursor 还是应该如何执行此操作?这有可能吗?这是个好主意吗?

I'm using Sqlite in Android and to get a value from the database I use something like this:

Cursor cursor = sqliteDatabase.rawQuery("select title,category from table", null);

int columnIndexTitle = cursor.getColumnIndex("title");
iny columnIndexCategory = cursor.getColumnIndex("category");

cursor.moveToFirst();
while (cursor.moveToNext()) {
    String title = cursor.getString(columnIndexTitle);  
    String category = cursor.getString(columnIndexCategory);    
}
cursor.close();

I want to create my own Cursor so that I can do getColumnIndex() and getString() with one method. Something like this:

String title = cursor.getString("title");

I want to create my own class that extends the cursor that I get from sqliteDatabase.rawQuery, but I'm not sure how to accomplish this. Should I extend SQLiteCursor or how should I do this? Is it even a possible and is it a good idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

少女七分熟 2024-11-08 08:38:23

我遇到了这个问题,正在寻找创建与 SQLiteDatabase 一起使用的自定义 Cursor 的最佳方法。就我而言,我需要游标的额外属性来携带额外的信息,因此我的用例与问题正文中的情况并不完全相同。发布我的发现希望对您有所帮助。

对我来说,棘手的部分是 SQLiteDatabase 查询方法返回一个 Cursor,我需要将一个自定义子类传递给 Cursor。

我在Android API中找到了解决方案:使用 CursorWrapper 类。它似乎就是专门为此而设计的。

类别:

public class MyCustomCursor extends CursorWrapper {

    public MyCustomCursor(Cursor cursor) {
        super(cursor);
    }

    private int myAddedAttribute;

    public int getMyAddedAttribute() {
        return myAddedAttribute;
    }

    public void setMyAddedAttribute(int myAddedAttribute) {
        this.myAddedAttribute = myAddedAttribute;
    }

}

用途:

public MyCustomCursor getCursor(...) {
    SQLiteDatabase DB = ...;
    Cursor rawCursor = DB.query(...);
    MyCustomCursor myCursor = new MyCustomCursor(rawCursor);
    myCursor.setMyAddedAttribute(...);
    return myCursor;
}

I came across this question looking for the best way to create a custom Cursor to use together with a SQLiteDatabase. In my case I needed an extra attribute to the Cursor to carry an additional piece of information, so my use case is not exactly as in the body of the question. Posting my findings in hope it will be helpful.

The tricky part for me was that the SQLiteDatabase query methods returns a Cursor, and I needed to pass on a custom subclass to Cursor.

I found the solution in the Android API: Use the CursorWrapper class. It seems to be designed exactly for this.

The class:

public class MyCustomCursor extends CursorWrapper {

    public MyCustomCursor(Cursor cursor) {
        super(cursor);
    }

    private int myAddedAttribute;

    public int getMyAddedAttribute() {
        return myAddedAttribute;
    }

    public void setMyAddedAttribute(int myAddedAttribute) {
        this.myAddedAttribute = myAddedAttribute;
    }

}

Usage:

public MyCustomCursor getCursor(...) {
    SQLiteDatabase DB = ...;
    Cursor rawCursor = DB.query(...);
    MyCustomCursor myCursor = new MyCustomCursor(rawCursor);
    myCursor.setMyAddedAttribute(...);
    return myCursor;
}
我很OK 2024-11-08 08:38:23

创建您自己的 getString 将导致每次调用都进行映射查找,而不仅仅是 getColumnIndex。

这是 SQLiteCursor.getColumnIndexAbstractCursor.getColumnIndex。如果有很多行,减少对此函数的调用将防止不必要的字符串处理和映射查找。

Creating your own getString will cause a map lookup for each call instead of only for getColumnIndex.

Here's the code for SQLiteCursor.getColumnIndex and AbstractCursor.getColumnIndex. If you have many rows, reducing calls to this function will prevent unnecessary string processing and map lookups.

巷雨优美回忆 2024-11-08 08:38:23

我不会扩展它,我会做一个助手:

class MartinCursor {
    private Cursor cursor;

    MartinCursor(Cursor cursor) {
        this.cursor = cursor;
    }

    String getString(String column) {
        ....
    }
}

或者就

class MartinCursorHelper {
    static String getString(Cursor cursor, String column) {
        ....
    }
}

我个人而言,我会做后者,除非你讨厌一直提供这个额外的参数。

编辑:我忘了提及 pydave 的要点:如果您在循环中调用它,那么您就会对性能产生明显的影响。首选方法是查找索引一次,缓存它,然后使用它。

I wouldn't extend it, I'd make a helper:

class MartinCursor {
    private Cursor cursor;

    MartinCursor(Cursor cursor) {
        this.cursor = cursor;
    }

    String getString(String column) {
        ....
    }
}

or

class MartinCursorHelper {
    static String getString(Cursor cursor, String column) {
        ....
    }
}

Personally, I'd do the latter, unless you hate providing this extra argument all the time.

EDIT: I forgot to mention pydave's important point: If you call this in a loop, you're setting yourself up for a noticeable performance impact. The preferred way is to lookup the index once, cache it, and use that instead.

二智少女 2024-11-08 08:38:23

您应该使用 DatabaseUtils.stringForQuery() Android SDK 中已有的静态方法可轻松检索值,此示例适用于 String 机器人,还有 Long

stringForQuery(SQLiteDatabase db, String query, String[] selectionArgs)

实用程序方法在数据库上运行查询的方法,以及返回第一行第一列的值。

像这样的东西

String myString=DatabaseUtils.stringForQuery(getDB(),query,selectionArgs);

You should make use of the DatabaseUtils.stringForQuery() static method that is already in Android SDK to easily retrieve a value, this example is for String bot there is also method for Long

stringForQuery(SQLiteDatabase db, String query, String[] selectionArgs)

Utility method to run the query on the db and return the value in the first column of the first row.

Something like

String myString=DatabaseUtils.stringForQuery(getDB(),query,selectionArgs);
疾风者 2024-11-08 08:38:23

遇到这个问题正在寻找不同的解决方案,但只是想添加这个,因为我相信答案并不令人满意。

您可以轻松创建自己的光标类。为了允许需要 Cursor 的函数接受它,它必须扩展 AbstractCursor。要解决系统不使用您的类的问题,您只需将您的类作为包装器即可。

这里有一个非常好的例子。
https:// /android.googlesource.com/platform/packages/apps/Contacts/+/8df53636fe956713cc3c13d9051aeb1982074286/src/com/android/contacts/calllog/ExtendedCursor.java

public class ExtendedCursor extends AbstractCursor {
/** The cursor to wrap. */
private final Cursor mCursor;
/** The name of the additional column. */
private final String mColumnName;
/** The value to be assigned to the additional column. */
private final Object mValue;
/**
 * Creates a new cursor which extends the given cursor by adding a column with a constant value.
 *
 * @param cursor the cursor to extend
 * @param columnName the name of the additional column
 * @param value the value to be assigned to the additional column
 */
public ExtendedCursor(Cursor cursor, String columnName, Object value) {
    mCursor = cursor;
    mColumnName = columnName;
    mValue = value;
}
@Override
public int getCount() {
    return mCursor.getCount();
}
@Override
public String[] getColumnNames() {
    String[] columnNames = mCursor.getColumnNames();
    int length = columnNames.length;
    String[] extendedColumnNames = new String[length + 1];
    System.arraycopy(columnNames, 0, extendedColumnNames, 0, length);
    extendedColumnNames[length] = mColumnName;
    return extendedColumnNames;
}

这就是其工作原理的总体思路。

现在来谈谈问题的实质。为了防止性能下降,请创建一个哈希来保存列索引。这将用作缓存。调用 getString 时,检查列索引的哈希值。如果不存在,则使用 getColumnIndex 获取并缓存。

很抱歉,我目前无法添加任何代码,但我使用的是移动设备,因此我稍后会尝试添加一些代码。

Came across this looking for a different solution, but just want to add this since I believe the answers are unsatisfactory.

You can easily create your own cursor class. In order to allow functions requiring Cursor to accept it, it must extend AbstractCursor. To overcome the issue of system not using your class, you simply make your class a wrapper.

There is a really good example here.
https://android.googlesource.com/platform/packages/apps/Contacts/+/8df53636fe956713cc3c13d9051aeb1982074286/src/com/android/contacts/calllog/ExtendedCursor.java

public class ExtendedCursor extends AbstractCursor {
/** The cursor to wrap. */
private final Cursor mCursor;
/** The name of the additional column. */
private final String mColumnName;
/** The value to be assigned to the additional column. */
private final Object mValue;
/**
 * Creates a new cursor which extends the given cursor by adding a column with a constant value.
 *
 * @param cursor the cursor to extend
 * @param columnName the name of the additional column
 * @param value the value to be assigned to the additional column
 */
public ExtendedCursor(Cursor cursor, String columnName, Object value) {
    mCursor = cursor;
    mColumnName = columnName;
    mValue = value;
}
@Override
public int getCount() {
    return mCursor.getCount();
}
@Override
public String[] getColumnNames() {
    String[] columnNames = mCursor.getColumnNames();
    int length = columnNames.length;
    String[] extendedColumnNames = new String[length + 1];
    System.arraycopy(columnNames, 0, extendedColumnNames, 0, length);
    extendedColumnNames[length] = mColumnName;
    return extendedColumnNames;
}

That's the general idea of how it will work.

Now to the meat of the problem. To prevent the performance hit, create a hash to hold the column indices. This will serve as a cache. When getString is called, check the hash for the column index. If it does not exist, then fetch it with getColumnIndex and cache it.

I'm sorry I can't add any code currently, but I'm on mobile so I'll try to add some later.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文