Android: How to create your own cursor class?

I use Sqlite on Android and to get the 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() one way. Something like that:

 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 do this. Should I extend SQLiteCursor or how to do it? Is it even possible and is it a good idea?

+6
source share
5 answers

Creating your own getString will result in a map search for each call, and not just for getColumnIndex.

Here is the code for SQLiteCursor.getColumnIndex and AbstractCursor.getColumnIndex . If you have many lines, reducing calls to this function will prevent unnecessary line processing and map search.

+3
source

I came across this question looking for the best way to create a custom Cursor for use with SQLiteDatabase . In my case, I needed an additional attribute for the Cursor to carry additional information, so my use case is not quite the same as in the body of the question. Drawing its conclusions in the hope, this will be useful.

The hard part for me was that the SQLiteDatabase query methods return a cursor, and I need to pass a custom subclass to Cursor.

I found a solution in the Android API: use the CursorWrapper class. It seems to be designed for just that.

Grade:

 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; } } 

Using:

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

I would not expand it, I would make an assistant:

 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 would do the latter if you do not hate to provide this additional argument all the time.

EDIT: I forgot to mention the important argument to pydave: if you call this in a loop, you tune yourself to a noticeable performance impact. The preferred way is to search the index once, caching and using it.

+2
source

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

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

A utility method to start a query in db and return a value in the first column of the first row.

Sort of

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

It's time to look for another solution, but I just want to add this, because I think the answers are unsatisfactory.

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

Here is a really good example. 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; } 

This is a general idea of ​​how this will work.

Now to the meat problems. To prevent performance gains, create a hash to hold the column indexes. This will serve as a cache. When getString is called, check the hash for the column index. If it does not exist, then extract it using getColumnIndex and cache it.

Sorry, I cannot add the code at present, but I am on a mobile device, so I will try to add it later.

0
source

Source: https://habr.com/ru/post/885750/


All Articles