Accessing data with android cursors
Upcoming SlideShare
Loading in...5
×
 

Accessing data with android cursors

on

  • 9,358 views

Android Application Development Training at Zybotech Solutions. Visit http://www.zybotech.in

Android Application Development Training at Zybotech Solutions. Visit http://www.zybotech.in

Statistics

Views

Total Views
9,358
Views on SlideShare
9,358
Embed Views
0

Actions

Likes
3
Downloads
142
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft Word

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Accessing data with android cursors Accessing data with android cursors Document Transcript

  • Android Application Development Training Tutorial For more info visit http://www.zybotech.in A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi
  • Accessing Data With Android CursorsWhat is SQLiteSQLite is an open-source server-less database engine. SQLite supports transacations and has no configurationrequired. SQLite adds powerful data storage to mobile and embedded apps without a large footprint.Creating and connecting to a databaseFirst import android.databse.sqlite.SQLiteDatabase into your application. Then use theopenOrCreateDatabase() method to create or connect to a database. Create a new project in Eclipse calledTestingData and select the API version of your choice. Use the package name higherpass.TestingData with anactivity TestingData and click finish.package higherpass.TestingData;import android.app.Activity;import android.os.Bundle;import android.database.sqlite.SQLiteDatabase;public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); SQLiteDatabase db; db = openOrCreateDatabase( "TestingData.db" , SQLiteDatabase.CREATE_IF_NECESSARY , null ); }}Add the android.database.sqlite.SQLiteDatabase to the standard imports from the new project. After thestandard layout setup initialize a SQLiteDatabase variable to hold the database instance. Next use theopenOrCreateDatabase() method to open the database. The openOrCreateDatabase() method expects thedatabase file first, followed by the permissions to open the database with, and an optional cursor factorybuilder.Where does Android store SQLite databases?Android stores SQLite databases in /data/data/[application package name]/databases.sqlite3 from adb shellbash-3.1$ /usr/local/android-sdk-linux/tools/adb devicesList of devices attachedemulator-5554 devicebash-3.1$ /usr/local/android-sdk-linux/tools/adb -s emulator-5554 shell A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi
  • # ls /data/data/higherpass.TestingData/databasesTestingData.db# sqlite3 /data/data/higherpass.TestingData/databases/TestingData.dbSQLite version 3.5.9Enter ".help" for instructionssqlite> .tablesandroid_metadata tbl_countries tbl_statesThe Google Android SDK comes with a utility adb. The adb tool can be used to browse and modify thefilesystem of attached emulators and physical devices. This example is a bit ahead of where we are as wehavent created the databases yet.Setting database propertiesThere are a few database properties that should be set after connecting to the database. Use the setVersion(),setLocale(), and setLockingEnabled() methods to set these properties. These will be demonstrated in thecreating tables example.Creating TablesTables are created by executing statements on the database. The queries should be executed with the execSQL()statement.package higherpass.TestingData;import java.util.Locale;import android.app.Activity;import android.os.Bundle;import android.database.sqlite.SQLiteDatabase;public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); SQLiteDatabase db; db = openOrCreateDatabase( "TestingData.db" , SQLiteDatabase.CREATE_IF_NECESSARY , null ); db.setVersion(1); db.setLocale(Locale.getDefault()); db.setLockingEnabled(true); final String CREATE_TABLE_COUNTRIES = "CREATE TABLE tbl_countries (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "country_name TEXT);"; final String CREATE_TABLE_STATES = "CREATE TABLE tbl_states (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi
  • + "state_name TEXT," + "country_id INTEGER NOT NULL CONSTRAINT " + "contry_id REFERENCES tbl_contries(id) " + "ON DELETE CASCADE);"; db.execSQL(CREATE_TABLE_COUNTRIES); db.execSQL(CREATE_TABLE_STATES); final String CREATE_TRIGGER_STATES = "CREATE TRIGGER fk_insert_state BEFORE " + "INSERT on tbl_states" + "FOR EACH ROW " + "BEGIN " + "SELECT RAISE(ROLLBACK, insert on table " + ""tbl_states" voilates foreign key constraint " + ""fk_insert_state") WHERE (SELECT id FROM " + "tbl_countries WHERE id = NEW.country_id) IS NULL; " + "END;"; db.execSQL(CREATE_TRIGGER_STATES); }}As before open the database with openOrCreateDatabase(). Now configure the database connection withsetVersion to set the database version. The setLocale method sets the default locale for the database andsetLockingEnabled enables locking on the database. Next we setup final String variables to hold the SQLitetable creation statements and execute them with execSQL.Additionally we manually have to create triggers to handle the foreign key relationships between the table. In aproduction application there would also need to be foreign key triggers to handle row updates and deletes. Theforeign key triggers are executed with execSQL just like the table creation.Inserting recordsAndroid comes with a series of classes that simplify database usage. Use a ContentValues instance to create aseries of table field to data matchings that will be passed into an insert() method. Android has created similarmethods for updating and deleting records. ContentValues values = new ContentValues(); values.put("country_name", "US"); long countryId = db.insert("tbl_countries", null, values); ContentValues stateValues = new ContentValues(); stateValues.put("state_name", "Texas"); stateValues.put("country_id", Long.toString(countryId)); try { db.insertOrThrow("tbl_states", null, stateValues); } catch (Exception e) { //catch code }Append this code to the previous example. First create a ContentValues object to store the data to insert and usethe put method to load the data. Then use the insert() method to perform the insert query into SQLite. Theinsert() function expects three parameters, the table name, null, and the ContentValues pairs. Also a long isreturned by the insert() function. This long will hold the primary key of the inserted row. A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi
  • Next we create a new ContentValues pair for the state and perform a second insert using the insertOrThrow()method. Using insertOrThrow() will throw an exception if the insert isnt successful and must be surrounded bya try/catch block. Youll notice that currently the application dies with an unhandled exception because thetables were trying to create already exist. Go back into the adb shell and attach to the SQLite database for theapplication and drop the tables.sqlite> drop table tbl_countries;sqlite> drop table tbl_states;Updating dataUpdating records is handled with the update() method. The update() function supports WHERE syntax similarto other SQL engines. The update() method expects the table name, a ContentValues instance similar to insertwith the fields to update. Also allowed are optional WHERE syntax, add a String containing the WHEREstatement as parameter 3. Use the ? to designate an argument replacement in the WHERE clause with thereplacements passed as an array in parameter 4 to update. ContentValues updateCountry = new ContentValues(); updateCountry.put("country_name", "United States"); db.update("tbl_countries", updateCountry, "id=?", new String[]{Long.toString(countryId)});First remove the table create statements from the code. We dont need to keep creating and dropping tables.Now create a new ContentValues instance, updateCountry, to hold the data to be updated. Then use theupdate() method to update the table. The where clause in parameter 3 uses replacement of the ? with the valuesstored in parameter 4. If multiple ? existed in the where statement they would be replaced in order by the valuesof the array.From the adb shell attach to the database and execute select * FROM tbl_countries; inside sqlite3.bash-3.1$ /usr/local/android-sdk-linux/tools/adb -s emulator-5554 shell# sqlite3 /data/data/higherpass.TestingData/databases/TestingData.dbSQLite version 3.5.9Enter ".help" for instructionssqlite> select * FROM tbl_countries;1|United StatesDeleting dataOnce data is no longer needed it can be removed from the database with the delete() method. The delete()method expects 3 parameters, the database name, a WHERE clause, and an argument array for the WHEREclause. To delete all records from a table pass null for the WHERE clause and WHERE clause argument array. db.delete("tbl_states", "id=?", new String[] {Long.toString(countryId)});Simply call the delete() method to remove records from the SQLite database. The delete method expects, thetable name, and optionally a where clause and where clause argument replacement arrays as parameters. Thewhere clause and argument replacement array work just as with update where ? is replaced by the values in thearray. A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi
  • Retrieving dataRetrieving data from SQLite databases in Android is done using Cursors. The Android SQLite query methodreturns a Cursor object containing the results of the query. To use Cursors android.database.Cursor must beimported.About CursorsCursors store query result records in rows and grant many methods to access and iterate through the records.Cursors should be closed when no longer used, and will be deactivated with a call to Cursor.deactivate() whenthe application pauses or exists. On resume the Cursor.requery() statement is executed to re-enable the Cursorwith fresh data. These functions can be managed by the parent Activity by calling startManagingCursor().package higherpass.TestingData;import java.util.Locale;import android.app.Activity;import android.os.Bundle;import android.content.ContentValues;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); SQLiteDatabase db; db = openOrCreateDatabase( "TestingData.db" , SQLiteDatabase.CREATE_IF_NECESSARY , null ); db.setVersion(1); db.setLocale(Locale.getDefault()); db.setLockingEnabled(true); Cursor cur = db.query("tbl_countries", null, null, null, null, null, null); cur.close(); }}Open the database as before. The query performed will return all records from the table tbl_countries. Nextwell look at how to access the data returned.Iterating through recordsThe Cursor class provides a couple of simple methods to allow iterating through Cursor data easily. UsemoveToFirst() to position the Cursor pointer at the first record then use the moveToNext() function to iterate A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi
  • through the records. The isAfterLast() method performs a check to see if the cursor is pointed after the lastrecord. When looping through records break the loop when this becomes false.First add the following attribute to the TextView element in the main layout. The main layout is the xml filelocated at res/layouts/main.xml. We need to give this TextView element an ID that we can reference to updatethe view. android:id="@+id/hello"Java code to iterate through entries in a cursor:package higherpass.TestingData;import java.util.Locale;import android.app.Activity;import android.os.Bundle;import android.widget.TextView;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view = (TextView) findViewById(R.id.hello); SQLiteDatabase db; db = openOrCreateDatabase( "TestingData.db" , SQLiteDatabase.CREATE_IF_NECESSARY , null ); db.setVersion(1); db.setLocale(Locale.getDefault()); db.setLockingEnabled(true); Cursor cur = db.query("tbl_countries", null, null, null, null, null, null); cur.moveToFirst(); while (cur.isAfterLast() == false) { view.append("n" + cur.getString(1)); cur.moveToNext(); } cur.close(); }}This code simply creates a cursor querying all the records of the table tbl_countries. The moveToFirst() methodis used to position the cursor pointer at the beginning of the data set. Then loop through the records in thecursor. The method isAfterLast() returns a boolean if the pointer is past the last record in the cursor. Use themoveToNext() method to traverse through the records in the cursor. A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi
  • Retrieving a specific recordThe cursor also allows direct access to specific records. Cursor cur = db.query("tbl_countries", null, null, null, null, null, null); cur.moveToPosition(0); view.append("n" + cur.getString(1)); cur.close();TransactionsSQLite also supports transactions when you need to perform a series of queries that either all complete or allfail. When a SQLite transaction fails an exception will be thrown. The transaction methods are all part of thedatabase object. Start a transaction by calling the beginTransaction() method. Perform the queries and then callthe setTransactionSuccessful() when you wish to commit the transaction. Once the transaction is complete callthe endTransaction() function. db.beginTransaction(); Cursor cur = null; try { cur = db.query("tbl_countries", null, null, null, null, null, null); cur.moveToPosition(0); ContentValues values = new ContentValues(); values.put("state_name", "Georgia"); values.put("country_id", cur.getString(0)); long stateId = db.insert("tbl_states", null, values); db.setTransactionSuccessful(); view.append("n" + Long.toString(stateId)); } catch (Exception e) { Log.e("Error in transaction", e.toString()); } finally { db.endTransaction(); cur.close(); }Start off with a call to beginTransaction() to tell SQLite to perform the queries in transaction mode. Initiate atry/catch block to handle exceptions thrown by a transaction failure. Perform the queries and then callsetTransactionSuccessful() to tell SQLite that our transaction is complete. If an error isnt thrown thenendTransaction() can be called to commit the transaction. Finally close the cursor when were finished with it.Built in android databasesThe Android Operating-System provides several built-in databases to store and manage core phone applicationdata. Before external applications may access some of these data sources access must be granted in theAndroidManifest.xml file in the root of the project. Some of the data applications can access are thebookmarks, media player data, call log, and contact data. Contact data not covered due to changes in the APIbetween 1.x and 2.0 version of Android. See the Android Working With Contacts Tutorial. Android providesbuilt in variables to make working with the internal SQLite databases easy. A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi
  • Access permissionsBefore a program accesses any of the internal Android databases the application must be granted access. Thisaccess is granted in the AndroidManifest.xml file. Before the application is installed from the market the userwill be prompted to allow the program to access this data. <uses-permissionandroid:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" /> <uses-permissionandroid:name="com.android.broswer.permission.WRITE_HISTORY_BOOKMARKS" /> <uses-permission android:name="android.permission.READ_CONTACTS" />These are some sample uses-permission statements to grant access to internal Android databases. These arenormally placed below the uses-sdk statement in the AndroidManifest.xml file. The first 2 grant read and writeaccess to the browser history and bookmarks. The third grants read access to the contacts. Well need to grantREAD access to the bookmarks and contacts for the rest of the code samples to work.Managed QueryManaged queries delegate control of the Cursor to the parent activity automatically. This is handy as it allowsthe activity to control when to destroy and recreate the Cursor as the application changes state.package higherpass.TestingData;import android.app.Activity;import android.os.Bundle;import android.provider.Browser;import android.widget.TextView;import android.database.Cursor;public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view = (TextView) findViewById(R.id.hello); Cursor mCur = managedQuery(android.provider.Browser.BOOKMARKS_URI, null, null, null, null ); mCur.moveToFirst(); int index = mCur.getColumnIndex(Browser.BookmarkColumns.TITLE); while (mCur.isAfterLast() == false) { view.append("n" + mCur.getString(index)); mCur.moveToNext(); } }}The managed query functions very similar to the query function we used before. When accessing Android builtin databases you should reference them by calling the associated SDK variable containing the correct databaseURI. In this case the browser bookmarks are being accessed by pointing the managedQuery() statement atandroid.provider.Browser.BOOKMARKS_URI. We left the rest of the parameters null to pull all results fromthe table. Then we iterate through the cursor records. Each time through the loop we append the title of the A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi
  • bookmark to the TextView element. If you know the name of a column, but not its index in the results use thegetColumnIndex() method to get the correct index. To get the value of a field use the getString() methodpassing the index of the field to return.BookmarksThe first Android database were going to explore is the browser bookmarks. When accessing the internalAndroid databases use the managedQuery() method. Android includes some helper variables inBrowser.BookmarkColumns to designate column names. They are Browser.BookmarkColumns.TITLE,BOOKMARK, FAVICON, CREATED, URL, DATE, VISITS. These contain the table column names for thebookmarks SQLite table.package higherpass.TestingData;import android.app.Activity;import android.os.Bundle;import android.provider.Browser;import android.widget.TextView;import android.database.Cursor;public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view = (TextView) findViewById(R.id.hello); String[] projection = new String[] { Browser.BookmarkColumns.TITLE , Browser.BookmarkColumns.URL }; Cursor mCur = managedQuery(android.provider.Browser.BOOKMARKS_URI, projection, null, null, null ); mCur.moveToFirst(); int titleIdx = mCur.getColumnIndex(Browser.BookmarkColumns.TITLE); int urlIdx = mCur.getColumnIndex(Browser.BookmarkColumns.URL); while (mCur.isAfterLast() == false) { view.append("n" + mCur.getString(titleIdx)); view.append("n" + mCur.getString(urlIdx)); mCur.moveToNext(); } }}This code works as before, with the addition of limiting return columns with a projection. The projection is astring array that holds a list of the columns to return. In this example we limited the columns to the bookmarktitle (Browser.BookmarkColumns.TITLE) and URL (Browser.BookmarkColumns.URL). The projection arrayis then passed into managedQuery as the second parameter. A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi
  • Media PlayerThe Android Media-player also uses SQLite to store the media information. Use this database to find mediastored on the device. Available fields are DATE_ADDED, DATE_MODIFIED, DISPLAY_NAME,MIME_TYPE, SIZE, and TITLE.package higherpass.TestingData;import android.app.Activity;import android.os.Bundle;import android.provider.MediaStore;import android.provider.MediaStore.Audio.Media;import android.widget.TextView;import android.database.Cursor;public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view = (TextView) findViewById(R.id.hello); String[] projection = new String[] { MediaStore.MediaColumns.DISPLAY_NAME , MediaStore.MediaColumns.DATE_ADDED , MediaStore.MediaColumns.MIME_TYPE }; Cursor mCur = managedQuery(Media.EXTERNAL_CONTENT_URI, projection, null, null, null ); mCur.moveToFirst(); while (mCur.isAfterLast() == false) { for (int i=0; i<mCur.getColumnCount(); i++) { view.append("n" + mCur.getString(i)); } mCur.moveToNext(); } }}The only differences here is that we use getColumnCount() to determine the number of columns in the returnedrecords and loop through displaying each column.Call LogIf granted permission Android applications can access the call log. The call log is accessed like otherdatastores.package higherpass.TestingData;import android.app.Activity;import android.os.Bundle;import android.provider.CallLog;import android.provider.CallLog.Calls; A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi
  • import android.widget.TextView;import android.database.Cursor;public class TestingData extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view = (TextView) findViewById(R.id.hello); String[] projection = new String[] { Calls.DATE , Calls.NUMBER , Calls.DURATION }; Cursor mCur = managedQuery(CallLog.Calls.CONTENT_URI, projection, Calls.DURATION +"<?", new String[] {"60"}, Calls.DURATION + " ASC"); mCur.moveToFirst(); while (mCur.isAfterLast() == false) { for (int i=0; i<mCur.getColumnCount(); i++) { view.append("n" + mCur.getString(i)); } mCur.moveToNext(); } }}This final example introduces the rest of the managedQuery() parameters. After the projection we pass aWHERE clause in the same way they were crafted in the update and delete sections earlier. After the whereclause comes the array of replacement arguments. Finally we pass in an order by clause to tell SQLite how tosort the results. This query only retrieves records for phone calls lasting less than 60 seconds and sorts them byduration ascending. A7, Stephanos Tower, Eachamukku, Kakkanadu,Kochi