Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
GitHub logo Twitter logo OReilly Book Cover Art

Exposing non-SQL data as an SQL Cursor

Author: Ian Darwin
Published? true
FormatLanguage: AsciiDoc

Problem:

You have non-SQL data, such as a list of files, and want to present it as a Cursor

Solution:

Subclass AbstractCursor and implement various required methods.

Discussion:

It is common to have data in a form other than a Cursor, but want to present it as a cursor for use in a ListView with an Adapter or a CursorLoader.

The AbstractCursor class facilitates this. While Cursor is an interface that you could implement directly, there are a number of routines therein that are pretty much the same in every implementation of Cursor, so they have been abstracted out and made into the AbstractCursor class.

In this short example we expose a list of filenames, which has the structure

  • id - sequence number
  • filename - full path
  • type - the filename extension We will expose this as a Cursor, and consume it in a SimpleCursorAdapter. First the start of the DataToCursor class:

    / Provide a Cursor from a fixed list of data column 1 - id column 2 - filename column 3 - file type / public class DataToCursor extends AbstractCursor {

    private static final String[] COLUMNNAMES = {"id", "filename", "type"};

    private static final String[] DATAROWS = { "one.mpg", "two.jpg", "tre.dat", "fou.git", };

    As you can see there are two arrays, one for the column names going across, and one for the rows going down. In this simple example we don't have to track the ID values (since they are the same as the index into the DATAROWS array) nor the file types (since they are the same as the filename extension).

    There are a few structural methods that are needed.

    @Override public int getCount() { return DATA.length; } @Override public int getColumnCount() { return COLUMNNAMES.length; }

    @Override public String[] getColumnNames() { return COLUMNNAMES; }

    The getColumnCount is obviously derivable but since it's constant, we override the method for efficiency reasons - probably not necessary in most applications.

    Then there are some necessary get methods, notably those for getting the type of a given column (is it numeric, string, etc), and those for getting the value of a given column in the current row. Nicely, the AbstractCursor handles all the moveToRow() and related methods, so we just have to call the inherited (and protected) method getPosition().

    @Override public int getType(int column) { switch(column) { case 0: return Cursor.FIELDTYPEINTEGER; case 1: case 2: return Cursor.FIELDTYPESTRING; default: throw new IllegalArgumentException(Integer.toString(column)); } }

    / Return the id value (the only integer-valued column). Conveniently, rows and array indices are both 0-based. / @Override public int getInt(int column) { int row = getPosition(); switch(column) { case 0: return row; default: throw new IllegalArgumentException(Integer.toString(column)); } } / SQLite ids are actually long, so make this work as well. This direct equivalence is usually not applicable; do not blindly copy. / @Override public long getLong(int column) { return getInt(column); }

    @Override public String getString(int column) { int row = getPosition(); switch(column) { case 1: return DATAROWS[row]; case 2: return extension(DATAROWS[row]); default: throw new IllegalArgumentException(Integer.toString(column)); } }

    The remaining methods aren't interesting; methods like getFloat(), getBlob() and so on, merely throw exceptions as, in this example, there are no columns of those types.

    The main activity shows nothing different than the other ListView examples in the ListView chapter: the data from the cursor is loaded into a ListView using a SimpleCursorAdapter (which is deprecated, but works fine for this example).

    The result is shown here:

    We have successfully shown this proof-of-concept of generating a Cursor without using SQLite). It would obviously be straightforward to turn this into a more dynamic file-listing utility, even a file manager. You'd want to use a CursorLoader instead of a SimpleCursorAdapter to make it complete.

    Download:

    The source code for this project is in the Android Cookbook repository at http://github.com/IanDarwin/Android-Cookbook-Examples, in the subdirectory DataToCursor.
    No records found.