Persistence in Android 5.x


Published on

The presentation deals with the problem of persistence when writing Android applications. After a general discussion on the capabilities of SQLite, the repository pattern (which allows the centralization all persistence concerns) is introduced. Then, the lifecycle of the SQLiteOpenHelper class is discussed, including how to correctly account for changes in the database schema between application updates. Finally, the concept of object-relational mapping (ORM) is introduced, together with a discussion and how the repository pattern helps isolating such a concern from the business logic code.

The source code is available at

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Persistence in Android 5.x

  1. 1. Persistence Ilio Catallo, Eleonora Ciceri – Politecnico di Milano,
  2. 2. TakeNotes current state ¤ TakeNotes is able to add and delete to-do items ¤ However, when the application is closed, the list is deleted, since items are not stored in persistent state ¤ Solution: use a database to store items ¤ Each time a to-do item is added to the list, it is stored in the database too ¤ When the application is launched, the list is loaded from the database 2
  3. 3. Persistence in Android 3
  4. 4. Android storage options ¤ Android provides several ways to store users and application data: ¤ Shared Preferences ¤ Internal / External Storage ¤ Network Connections ¤ SQLite Databases ¤ Databases are particularly suited when storing large amounts of the same structured data 4
  5. 5. Example: TakeNotes # to-do item Text 1 Send an e-mail to T.A.’s 2 Deliver project specifications 3 Buy milk 5 ¤ In TakeNotes, we need at least to store the text of each to-do item in the list
  6. 6. Introducing SQLite ¤ SQLite is a SQL databaseengine ¤ It is implemented as a C library ¤ SQLite’s main features: ¤ Open-source ¤ Standard-compliant ¤ Lightweight ¤ Single-tier ¤ SQLite is natively supported in Android, and it provides a a robust persistence layer over which you have total control 6
  7. 7. Setting up a database ¤ No database is automatically provided with the application, If you want to use SQLite, you have to: ¤ Create your own database ¤ Create tables ¤ Populate it with data ¤ Any databases will be accessible by name to any class in the application, but not outside the application 7
  8. 8. Persistence layer 8
  9. 9. Business logic layer vs. persistence layer ¤ You do not want the business logic code to deal directly with the problem of persisting data 9 Activity 3 Data source Activity 1 Activity 2 SQL statements are scattered everywhere in the codebase If you change the relational model you have to change the code everywhere
  10. 10. Business logic layer vs. persistence layer ¤ It would be better have a central authority responsible for persisting the data ¤ The business logic can interact with such a central authority, without caring of how the data are actually persisted 10 Central authority (repository) Data source Activity 1 Activity 2 Activity 3 Businesslayer
  11. 11. The Repository pattern ¤ Since the central authority is usually referred to as the repository, the resulting design pattern is called the Repository pattern ¤ The repository act as a mediator between the business logic layer and the data source layer ¤ The repository is usually implemented as a helper class whose methods will be invoked by the business layer code 11
  12. 12. The SQLite repository class ¤ The recommended method to create a new SQLite database is to create a subclass of SQLiteOpenHelper ¤ SQLiteOpenHelper is the repository class that manages interactions with the database ¤ The subclass of SQLiteOpenHelper will: ¤ Take care of opening the database if it exists ¤ Create the database if it does not exist ¤ Upgrade the database if it is necessary 12
  13. 13. The SQLite repository class ¤ DatabaseHandler is the repository class for our application ¤ It is obtained by extending the SQLiteOpenHelper class provided by Android 13
  14. 14. Creating a database 14
  15. 15. Anatomy of a SQLite database ¤ SQLite databases are stored in the /data/data/package_name/databases folder on your device or emulator ¤ Each SQLite database is characterized by the following properties: ¤ A human-readable name ¤ A version number 15
  16. 16. Creating databases ¤ If not already present, the database is created on disk the first time the application tries to access the data ¤ The database is upgraded every time a mismatch between version numbers is detected. ¤ Typical use case: ¤ As a new app update requires a change in the database schema, the version number is increased ¤ The app detects the mismatch and upgrades the schema of the locally stored database 16
  17. 17. Creatingdatabases 17 Application starts DB exists? Create the DB on disk No Yes Is version number the same? Yes Upgrade the DB on disk No First access
  18. 18. Creating databases ¤ The create/upgrade lifecycle is implemented in the repository class by means of three methods: ¤ The constructor ¤ The onCreate() method ¤ the onUpdate() method 18
  19. 19. Creatingdatabases 19 Application starts DB exists?onCreate() No Yes Is version number the same? Yes onUpgrade() No First access DatabaseHandler()
  20. 20. Overriding the constructor ¤ The repository class’ constructor informs the system that the application wants to create a database ¤ Together with other parameters, it specifies: ¤ The name of the database ¤ The current version number 20
  21. 21. Overriding the constructor 21 Constants are usually stored as static data members The Context object is needed to actually create the database (see reference) An optional CursorFactory, typically just pass null
  22. 22. Overriding the onCreate() method ¤ The onCreate() method is called when the database is created for the first time ¤ The method is responsible for the creation of tables ¤ Remember: the method will not be called if no operation is performed on the database 22
  23. 23. Overriding the onCreate() method 23 a new table named todo is createdthe execSQL() method works for any SQL that does not return a result
  24. 24. Overriding the onUpgrade() method ¤ The onUpgrade() method upgrades the existing database to conform to the new version ¤ This method should drop tables, add tables, or do anything else it needs to upgrade to the new schema version ¤ Remember: the method will not be called if no operation is performed on the database 24
  25. 25. Overriding the onUpgrade() method 25 Snippet taken from: The database is upgraded from oldVersion to newVersion by cascading upgrade statement
  26. 26. Overriding the onUpgrade() method ¤ The simplest upgrading policy is to drop the old table and create a new one 26 The todo table is droppedThe todo table is created from scratch
  27. 27. Obtaining the database ¤ To access a database using the repository class, call: ¤ getReadableDatabase() to obtain a read-only instance of the database ¤ getWritableDatabase() to obtain a read-write instance of the database ¤ After invoking one of the two methods: ¤ If the DB does not exist, onCreate() will be called ¤ If the DB needs to be upgraded, onUpgrade() will be called 27
  28. 28. Creatingdatabases 28 Application starts DB exists? onCreate() No Yes Is version number the same? Yes onUpgrade() No First access DatabaseHandler() getWritableDatabase()
  29. 29. Interacting with the database 29
  30. 30. Object model vs. Relational model ¤ The data you want to persist are usually encoded as class instances, i.e., as objects ¤ Example: starting from TakeNotes v4, the to-do items are modeled as instances of a ToDo class 30
  31. 31. Object model vs. Relational model ¤ On the other hand, relation databases organize information as tables and rows ¤ Example: the database for TakeNotes v4 can be made of just one table named todo 31 # to-do item Text 1 Send an e-mail to T.A.’s 2 Deliver project specifications 3 Buy milk
  32. 32. Object-Relational Mapping ¤ As such: ¤ The business logic code deals with classes and objects ¤ The database deals with tables and rows ¤ We need a mediator to manage the automatic transformation of objects to tuples and vice versa ¤ The technique of mapping objects to tuples (and vice versa) is known as object-relational mapping (ORM) 32
  33. 33. Object-Relational Mapping ¤ A possible solution is to make the repository responsible of providing a object-relation mapping (ORM) mechanism 33 Central authority (repository) Data source Activity 1 Activity 2 Activity 3 Businesslayer Java objects Tables and rows
  34. 34. Object-Relational Mapping ¤ The issue of mapping objects to tuples is a non-trivial one ¤ Developers spend effort in writing lots of code to convert row and column data into objects ¤ Android put the entire burden on the developers ¤ It is up to the developer to correctly perform the mapping ¤ Third-party libraries are available 34
  35. 35. Writing data into the database ¤ The repository class should expose methods to persist objects into the database ¤ Example: In TakeNotes, business logic code can persist a ToDo class instances by invoking the addToDo method on the repository class instance 35
  36. 36. Transforming objects into tuples ¤ The repository class needs to convert objects into tuples ¤ Android represents tuples as ContentValues class instances 36 not needed if the id column is auto-incremented
  37. 37. Transforming objects into tuples ¤ Once a tuple has been populated, it is ready to be inserted into the database 37 Object-relational mapping
  38. 38. The NULL value hack ¤ While permitted in SQL, SQLite forbids to insert an empty tuple, i.e., an empty ContentValues object ¤ If you pass an empty ContentValues to insert(), you must also provide the name of a column that SQLite will explicitly set to NULL 38 Name of the column that will be set to NULL just pass null if you know that the ContentValues is not empty
  39. 39. Querying the database ¤ There exist two ways of querying the database: ¤ Use rawQuery() to execute a SQL statement directly ¤ use query() to build up a query from its component parts 39
  40. 40. Querying with rawQuery() ¤ The most immediate approach for querying the database is to use rawQuery() 40 In case of parametric queries, parameter values must be specified here
  41. 41. Querying with query() ¤ The query() method takes the discrete pieces of a SELECT statement and builds the query from them. ¤ The pieces are: ¤ the name of the table to query against ¤ The list of columns to retrieve ¤ The WHERE clause (with possible positional parameters) ¤ The positional parameter values ¤ The GROUP BY clause, if any ¤ The HAVING clause, if any ¤ The ORDER BY clause, if any 41
  42. 42. Querying with query() 42 SELECT * FROM todo WHERE id=1 OR id=2 ORDER BY clause HAVING clause GROUP BY clause equivalent to SELECT *
  43. 43. The result set ¤ A query result set are returned as a Cursor object ¤ A Cursor contains method for iterating over results ¤ With a Cursor you can: ¤ Find how many rows are in the result set via getCount() ¤ Iterate over the tuples via moveToFirst(), moveToNext() and isAfterLast() ¤ Re-execute the query that created the cursor via requery() ¤ Release the cursor’s resources via close() 43
  44. 44. Result sets as lists of objects ¤ The repository class is responsible for transforming tuples in the result set into a list of objects ¤ The repository class exposes methods that return collection of objects 44
  45. 45. Result sets as lists of objects 45 Object-relational mapping
  46. 46. References 46
  47. 47. References ¤ Reto Meier, Professional Android 4 Application development 3rd Ed., Wrox ¤ SQLiteOpenHelper class reference: ase/sqlite/SQLiteOpenHelper.html ¤ SQLiteDatabase class reference: ase/sqlite/SQLiteDatabase.html 47
  48. 48. References ¤ Android API Guides, Storage Options storage.html ¤ Android SQLite Database Tutorial: tutorial/ ¤ MSDN, the Repository pattern ¤ Martin Fowler, The Repository pattern 48