Pages

Showing posts with label sqlite. Show all posts
Showing posts with label sqlite. Show all posts

Thursday, April 21, 2016

Using SQLite Database with Android

Android default Database engine is Lite. SQLite is a lightweight transactional database engine that occupies small amout of disk storage and memory, so its a perfect choice for creating databases on many mobile operating systems such as Android, iOS.

Things to consider when dealing with SQLite:
  1. Data type integrity is not maintained in SQLite, you can put a value of a certain data type in a column of another dataype (put string in an integer and vice versa).
  2. Referential integrity is not maintained in SQLite, there is no FOREIGN KEY constraints or JOIN statements.
  3. SQLite Full Unicode support is optional and not installed by default.

In this tutorial we will create a simple database application to store employees data.

the DB has:
Tables:
  1. Employees
  2. Dept.
Views:
  1. ViewEmps: to display employees and their relative departments.


Creating SQLite Database

By default SQLite on Android does not have a management interface or an application to create and manage data bases from, so were going to create the database ourselves by code.

First we will create a class that handles all the operations required to deal with the database such as creating the database, creating tables, inserting and deleting records and so on.

The first step is to create a class that inherits from SQLiteOpenHelper class. this class provides two methods to override to deal with the database:
  1. onCreate(SQLiteDatabase db): invoked when the database is created, this is where we can create tables and columns to them, create views or triggers.
  2. onUpgrade(SQLiteDatabse db, int oldVersion, int newVersion): invoked when we make a modification to the database such as altering, dropping , creating new tables.


our class will have the following members
public class DatabaseHelper extends SQLiteOpenHelper {

static final String dbName="demoDB";
static final String employeeTable="Employees";
static final String colID="EmployeeID";
static final String colName="EmployeeName";
static final String colAge="Age";
static final String colDept="Dept";

static final String deptTable="Dept";
static final String colDeptID="DeptID";
static final String colDeptName="DeptName";

static final String viewEmps="ViewEmps";

The Constructor:
public DatabaseHelper(Context context) {
super(context, dbName, null,33);
}

The constructor of the super class has the following parameters:

Context con: the context attached to the database.
dataBaseName: the name of the database.
CursorFactory: some times we may use a class that extends the Cursor class to implement some extra validations or operations on the queries run on the database. In this case we pass an instance of CusrsorFactory to return a reference to our derived class to be used instead of the default cursor,
In this example we are going to use the standard Cursor Interface to retrieve results, so the CursorFactory parameter is going to be null.

Version: the version of the schema of the database.

The constructor creates a new blank database with the specified name and version.

Creating the database:

The first superclass method to override is onCreate(SQLiteDatabase db):
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub

db.execSQL("CREATE TABLE "+deptTable+" ("+colDeptID+ " INTEGER PRIMARY KEY , "+
colDeptName+ " TEXT)");

db.execSQL("CREATE TABLE "+employeeTable+" ("+colID+" INTEGER PRIMARY KEY AUTOINCREMENT, "+
colName+" TEXT, "+colAge+" Integer, "+colDept+" INTEGER NOT NULL ,FOREIGN KEY ("+colDept+") REFERENCES "+deptTable+" ("+colDeptID+"));");


db.execSQL("CREATE TRIGGER fk_empdept_deptid " +
" BEFORE INSERT "+
" ON "+employeeTable+

" FOR EACH ROW BEGIN"+
" SELECT CASE WHEN ((SELECT "+colDeptID+" FROM "+deptTable+" WHERE "+colDeptID+"=new."+colDept+" ) IS NULL)"+
" THEN RAISE (ABORT,Foreign Key Violation) END;"+
" END;");

db.execSQL("CREATE VIEW "+viewEmps+
" AS SELECT "+employeeTable+"."+colID+" AS _id,"+
" "+employeeTable+"."+colName+","+
" "+employeeTable+"."+colAge+","+
" "+deptTable+"."+colDeptName+""+
" FROM "+employeeTable+" JOIN "+deptTable+
" ON "+employeeTable+"."+colDept+" ="+deptTable+"."+colDeptID
);
//Inserts pre-defined departments
InsertDepts(db);

}


the method creates tables with columns,a view and a trigger.

The method is invoked when the database is created. So we create our table and specify the columns.

This method is invoked when the database does not exist on the disk, it’s executed only once on the same device at the first time the application is run on the device.

Upgrading the database:

some times we want to upgrade the database by changing the schema, add new tables or change column data types.
this is done by overriding onUpdate(SQLiteDatabase db,int old Version,int newVerison) method:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub

db.execSQL("DROP TABLE IF EXISTS "+employeeTable);
db.execSQL("DROP TABLE IF EXISTS "+deptTable);

db.execSQL("DROP TRIGGER IF EXISTS dept_id_trigger");
db.execSQL("DROP TRIGGER IF EXISTS dept_id_trigger22");
db.execSQL("DROP TRIGGER IF EXISTS fk_empdept_deptid");
db.execSQL("DROP VIEW IF EXISTS "+viewEmps);
onCreate(db);
}


This method is invoked when the version number specified in the constructor of the class changes.

when you want to append a change to your database you must change the version number in the constructor of the class:

so when you pass the constructor a version number of 2:
public DatabaseHelper(Context context) {
super(context, dbName, null,2);

// TODO Auto-generated constructor stub
}
instead of 1:
super(context, dbName, null,2);
the application understands that you want to upgrade the database and onUpgrade method will be invoked

A typical implementation of this method is to drop the tables and create them again with the additional modifications.

Managing Foreign-Key Constraints:

we mentioned before that SQLite 3 by default does not support foreign key constraint, however we can force such a constraint using TRIGGERS:

we will create a trigger that ensures that when a new Employee is inserted his/her Dept value is present in the original Dept table.

the sql statement to create such a trigger would be like this:
CREATE TRIGGER fk_empdept_deptid Before INSERT ON Employees 
FOR EACH ROW BEGIN
SELECT CASE WHEN ((SELECT DeptID FROM Dept WHERE DeptID =new.Dept ) IS NULL)
THEN RAISE (ABORT,Foreign Key Violation) END;
END

in onCreate method we created this trigger like this:
db.execSQL("CREATE TRIGGER fk_empdept_deptid " +
" BEFORE INSERT "+
" ON "+employeeTable+

" FOR EACH ROW BEGIN"+
" SELECT CASE WHEN ((SELECT "+colDeptID+" FROM "+deptTable+" WHERE "+colDeptID+"=new."+colDept+" ) IS NULL)"+
" THEN RAISE (ABORT,Foreign Key Violation) END;"+
" END;");


Executing SQL statements:

now lets begin executing basic sql statements. you can execute any sql statement that is not a query whether it is insert, delete, update or anything using db.execSQL(String statement) method like when we did when creating the database tables:
db.execSQL("CREATE TABLE "+deptTable+" ("+colDeptID+ " INTEGER PRIMARY KEY , "+
colDeptName+ " TEXT)");

Inserting records:

we insert records to the databse using the following code for example to insert records in the Dept table:
SQLiteDatabase db=this.getWritableDatabase();
ContentValues cv=new ContentValues();
cv.put(colDeptID, 1);
cv.put(colDeptName, "Sales");
db.insert(deptTable, colDeptID, cv);

cv.put(colDeptID, 2);
cv.put(colDeptName, "IT");
db.insert(deptTable, colDeptID, cv);
db.close();

notice that we need to call this.getWritableDatabase() to open the connection with the database for reading/writing.
the ContentValues.put has two parameters: Column Name and the value to be inserted.

also it is a good practice to close the database after executing statements.

Updating values:

to execute an update statement we have two ways

  1. to execute db.execSQL
  2. to execute db.update method:
public int UpdateEmp(Employee emp)
{
SQLiteDatabase db=this.getWritableDatabase();
ContentValues cv=new ContentValues();
cv.put(colName, emp.getName());
cv.put(colAge, emp.getAge());
cv.put(colDept, emp.getDept());
return db.update(employeeTable, cv, colID+"=?", new String []{String.valueOf(emp.getID())});

}

the update method has the following parameters:

  1. String Table: the table to update a value in
  2. ContentValues cv: the content values object that has the new values
  3. String where clause: the WHERE clause to specify which record to update.
  4. String[] args: the arguments of the WHERE clause.
Deleteing rows:

as in update to execute a delete statement we have two ways

  1. to execute db.execSQL
  2. to execute db.delete method:
public void DeleteEmp(Employee emp)
{
SQLiteDatabase db=this.getWritableDatabase();
db.delete(employeeTable,colID+"=?", new String [] {String.valueOf(emp.getID())});
db.close();
}

the delete method has the same parameters as the update method.

Executing queries:

to execute queries there are two methods:

  1. Execute db.rawQuery method.
  2. Execute db.query method.

to execute a raw query to retreive all departments
Cursor getAllDepts()
{
SQLiteDatabase db=this.getReadableDatabase();
Cursor cur=db.rawQuery("SELECT "+colDeptID+" as _id, "+colDeptName+" from "+deptTable,new String [] {});

return cur;
}

the rawQuery method has two parameters:

  1. String query: the select statement.
  2. String[] selection args: the arguments if a WHERE clause is included in the select statement.

Notes:
  1. The result of a query is returned in Cursor object.
  2. In a select statement if the primary key column (the id column) of the table has a name other than _id then you have to use an alias in the form SELECT [Column Name] as _id
  3. cause the Cursor object always expects that the primary key column has the name _id or it will throw an exception .


another way to perform a query is to use a db.query method.

a query to select all employees in a certain department from a view would be like this:
public Cursor getEmpByDept(String Dept)
{
SQLiteDatabase db=this.getReadableDatabase();
String [] columns=new String[]{"_id",colName,colAge,colDeptName};
Cursor c=db.query(viewEmps, columns, colDeptName+"=?", new String[]{Dept}, null, null, null);
return c;
}

the db.query has the folowing parameters:
  1. String Table Name: the name of the table to run the query against.
  2. String [ ] columns: the projection of the query i.e the columns to retrieve.
  3. String WHERE clause: where clause, if none pass null.
  4. String [ ] selection args: the parameters of the WHERE clause.
  5. String Group by: a string specifying group by clause.
  6. String Having: a string specifying HAVING clause.
  7. String Order By by: a string Order By by clause.
Managing Cursors:

Result sets of queries are returned in Cursor objects.
there are some common methdos that you will use with cursors:
  1. boolean moveToNext(): moves the cursor by one record in the result set, returns false if moved past the last row in the result set.
  2. boolean moveToFirst(): moves the cursor to the first row in the result set, returns false if the result set is empty.
  3. boolean moveToPosition(int position): moves the cursor to a certain row index within the boolean result set, returns false if the position is un-reachable
  4. boolean moveToPrevious():moves the cursor to the preevious row in the result set, returns false if the cursor is past the first row.
  5. boolean moveToLast():moves the cursor to the lase row in the result set, returns false if the result set is empty.

there are also some useful methods to check the position of a cursor:
boolean isAfterLast(), isBeforeFirst, isFirst,isLast and isNull(columnIndex).


also if you have a result set of only one row and you need to retreive values of certain columns, you can do it like this:
public int GetDeptID(String Dept)
{
SQLiteDatabase db=this.getReadableDatabase();
Cursor c=db.query(deptTable, new String[]{colDeptID+" as _id",colDeptName},colDeptName+"=?", new String[]{Dept}, null, null, null);
//Cursor c=db.rawQuery("SELECT "+colDeptID+" as _id FROM "+deptTable+" WHERE "+colDeptName+"=?", new String []{Dept});
c.moveToFirst();
return c.getInt(c.getColumnIndex("_id"));

}

we have Cursor.getColumnIndex(String ColumnName) to get the index of a column.

then to get the value of a certain column we have Cursor.getInt(int ColumnIndex) method.
also there are getShort,getString,getDouble, getBlob to return the value as a byte array.

its a good practice to close() the cursor after using it.

Download a sample application on using database in Android from here
Read More..

Sunday, April 17, 2016

SQLite DB Example Android Developer Tutorial Part 12


There are 4 ways of storing data on the android platform:

  • 1.    Preferences
  • 2.    SQLite Database
  • 3.    Files
  • 4.    Network

A word about each of them here and then I will move on to an example that shows how to work with SQLite DB that comes along with the android platform.


Preferences–
Basically used for storing user preferences for a single application or across applications for a mobile. This is typically name-value pairs accessible to the context.


Databases –
Android supports creating of databases based on SQLite db. Each database is private to the applications that creates it

Files –
Files can be directly stored on the mobile or on to an extended storage medium. By default other applications cannot access it.


Network –
Data can be stored and retrieved from the network too depending on the availability.


If an application wants to store and retrieve data for its own use, without having to share the data across applications, it can access the SQLite DB directly. There is no need of a content provider. We have seen in an earlier post how to use content providers.


In this example, we will do the following:
1.    Create a database (typically a one time activity)
2.    Create a table (typically a one time activity)
3.    Insert values into the table
4.    Retrieve the values from the table
5.    Display the retrieved values as a List view
6.    Delete all the records from the table before closing the connection to the database


Step 1: Create a database:


   sampleDB =  this.openOrCreateDatabase(SAMPLE_DB_NAME, MODE_PRIVATE, null);

This opens a database defined in the constant SAMPLE_DB_NAME, if it already exists. Else it creates a database and opens it. The second parameter is operating mode : MODE_PRIVATE meaning it is accessible to only this context. The other modes are and MODE_WORLD_WRITABLE. MODE_WORLD_READABLE


Step 2: Create a Table:


sampleDB.execSQL("CREATE TABLE IF NOT EXISTS " +
                        SAMPLE_TABLE_NAME +
                        " (LastName VARCHAR, FirstName VARCHAR," +
                        " Country VARCHAR, Age INT(3));");


Step 3: Insert values into the table:


sampleDB.execSQL("INSERT INTO " +
                        SAMPLE_TABLE_NAME +
                        " Values (Makam,Sai Geetha,India,25);");


Step 4: Retrieve values


Cursor c = sampleDB.rawQuery("SELECT FirstName, Age FROM " +
                        SAMPLE_TABLE_NAME +
                        " where Age > 10 LIMIT 5", null);
           
      if (c != null ) {
            if  (c.moveToFirst()) {
                  do {
String firstName = c.getString(c.getColumnIndex("FirstName"));
                  int age = c.getInt(c.getColumnIndex("Age"));
                  results.add("" + firstName + ",Age: " + age);
                  }while (c.moveToNext());
            }
       }


Step 5: Display the values as a list
           
       this.setListAdapter(newArrayAdapter<String>(this, android.R.layout.simple_list_item_1,results));


The statement displays it as a list as the class extends a ListActivity.


Step 6: Delete the values from the table in the finally part of the try block


finally {
            if (sampleDB != null)
                  sampleDB.execSQL("DELETE FROM " + SAMPLE_TABLE_NAME);
                  sampleDB.close();
        }


It is as simple as this to work with the SQLite DB even in android. No different from a desktop application. However, there are various overloaded methods of query() provided by the SQLIteDatabase class which can be more optimally used instead of execSQL.


The complete code for this example is downloadable here.

Read More..

Wednesday, March 30, 2016

Android Developers Backstage Episode 10 ART pART 1

Tor and Chet may not know ART, but they know what they like. In this episode, the first in a two-pART series, they talk with Anwar Ghuloum from the ART, or Android Runtime team. ART is the new runtime for Android, which came online in the KitKat release as an alternative to Dalvik. Now ART is not only enabled by default: it’s the only runtime. We’ll talk about what it is, how it works, why it’s better, and the future and very meaning of ART in modern society.

Subscribe to the podcast feed or download the audio file directly.

ARTicles:
Introducing ART: http://source.android.com/devices/tech/dalvik/art.html
Verifying App Behavior: http://developer.android.com/guide/practices/verifying-apps-art.html

Google I/O 2014 Session:
The ART Runtime: https://www.youtube.com/watch?v=EBlTzQsUoOw

Other Resources:
Systrace: http://developer.android.com/tools/help/systrace.html

Tor: google.com/+TorNorbye
Chet: google.com/+ChetHaase
Read More..

Friday, February 26, 2016

Android UI – Inflate from XML Dynamic UI Creation


We have seen that we can declare User Interface in Android through XML or we can even create the UI Programmatically. Now, we will see how we can mix the two and use it for building dynamic User Interfaces. One example of such a case would be when on a particular action of the user on one of the UI elements, you need more UI elements to appear on the same screen. How do we achieve this?
You can do it in two ways:
1.       The dynamic part of the UI can be created programmatically. However we saw in my earlier tutorial that it is not a very good way to mix UI and code.  So, we can
2.       Define the dynamic UI too as an XML and use XML inflation to include it into the existing UI.
We will see how to do the 2ndway, which probably is a good practice too.
As always, again a very simple example. Assume I have a very simple linear layout. In that I want to include a button. I can do it as part of the mail XML itself. However, assume that this button is supposed to be reused in many activities and hence I have defined it as a separate XML. How do I include it into the main XML?
So, here is the main.xml
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout >="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/layout1"
    >
</LinearLayout>
Here is the buttons.xml that is also created in the res/layout folder:
<?xml version="1.0"encoding="utf-8"?>

<Button >="http://schemas.android.com/apk/res/android"
        android:id="@+id/button_small_left"
 style="?android:attr/buttonStyleSmall"
        android:text="Press to close"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
And here is the Activity’s onCreate(…) method of the InflateView class:
    public voidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        final LayoutInflater  inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        Button b = (Button)inflater.inflate(R.layout.buttons,
                null);
       
        lLayout = (LinearLayout)findViewById(R.id.layout1);
        lLayout.addView(b);
First 3 lines must be familiar. In the 4thline, I am getting a handle to the LayoutInflater through the getSystemService(…) method.  This inflater has a method inflate to which I pass the buttons.xml by passing the parameter R.layout.buttons. Then, I try to append this button to the Linear Layout that already exists and is set as the view in line 2 setContentView(R.layout.main). How to append? I get a handle to the LinearLayoutlLayout and add the new button to it in the last line!
That simple to inflate an XML and append it to an existing view!
However, I have gone ahead and added another bit to this program as shown below:
        b.setOnClickListener(new OnClickListener() {
           
            public void onClick(View v) {
                  //restrict to adding only 1 textview child element
                  if (lLayout.getChildAt(2) == null)
                  {
                  TextView tv = (TextView)inflater.inflate(R.layout.text, null);
                  lLayout.addView(tv);
                  }
            }
        });
On the click of this dynamically added button, I am showing how we can add more to the UI dynamically through inflation. Assume, on the click of the button, you want to show some new text. This TextView is defined in another XML called text.xml which is also in the res/layout folder.
So, I am inflating from this XML and appending it to the LinearLayout view. So, a lot can be achieved for dynamic UI through inflation.

You can download the complete sample code here.
Read More..