Sunday, May 20, 2012

SQLLite Database in Android

This is fairly complex for what is really a simple thing. This example creates a database to store CDs and Tracks. The main form shows you what CDs are in the database. If you tap (or in the emulator click) on a CD it takes you to the detail view where you can see the CD title, artist and all the tracks. Also at the bottom of the main form is a clickable TextView that takes you to an Activity where you can input a new Cd and tracks.

You can get the complete project in a zip file here

Here are screen shots of the views:

the main view with some data already in the database


here is a view of the detail screen


And here is the input screen


Creating the Database

The first thing you need to do is create the database and the tables. The best way to do this is to use a SQLHelper class which extends SQLLiteOpenHelper. Here is the code for my class


package com.spconger.databasetest;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class SQLHelper extends SQLiteOpenHelper{
/*
 * this class creates the database and its tables. it 
 * extends the SQLiteOpenHelper class
 * which give access to the sql lite database
 */
 
 //create the database
 private static final String DATABASE_NAME = "Cds.db";
 private static final int DATABASE_VERSION = 1;

 // Table name
 public static final String CD_TABLE = "CD";
 public static final String TRACK_TABLE = "Tracks";
 
 // CD Table columns
 public static final String CD_TITLE = "CDTitle";
 public static final String CD_ARTIST = "Artist";
 
 //Track table columns
 public static final String CD_ID="CdId";
 public static final String TRACK_TITLE = "TrackTitle";
 
 
 //required constructor
 public SQLHelper(Context context) {
  super(context, DATABASE_NAME, null, DATABASE_VERSION);
  // TODO Auto-generated constructor stub
 }

 @Override
 public void onCreate(SQLiteDatabase db) {
  // create the CD table
  String sql_CD = "create table " + CD_TABLE + "( " + 
  CD_ID + " integer primary key autoincrement, " +
  CD_TITLE + " text not null, " + 
  CD_ARTIST + " text not null, " + 
  "unique (" + CD_TITLE + "))";

db.execSQL(sql_CD); //add to the database

//create the Track table
String sql_Track = "create table " + TRACK_TABLE + "( " +  
CD_ID + " integer, " + 
TRACK_TITLE + " text not null, " + 
"foreign key (" + CD_ID+ ") references " + CD_TABLE + "(_id));";

db.execSQL(sql_Track);
  
 }

 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  // this method is used to save data, drop and recreate tables when
  //the database software is upgraded
  
 }

}



The Android App

To work with the database, we create a CD class to store CD and track information. The tracks are stored in a listArray. the fields are entered at the constructor, and each has a get accessor. There is a method to add tracks to the arraylist, and a method that loops through the array list and writes all the tracks to the a string with line breaks after each track. I will not display that class here, but it is available in the zip file.

In the main activity, We make contact with the database and read all the data into a listarray of CDs. Then we display the titles on the screen. Here is the code to do that. It is a lot of code


 private void initPatientList()
 {
     //initialize the list view
  cdListView = (ListView) findViewById(R.id.CdListView);
  cds = new ArrayList<CD>();
  
  //link to the database
  SQLHelper sqlHelper = new SQLHelper(DatabaseTestActivity.this);
  SQLiteDatabase db = sqlHelper.getWritableDatabase();           
  
  //create a cursor to move through the data
        Cursor cdCursor = db.query(SQLHelper.CD_TABLE, 
          new String[] {"*"}, "", null, null, null, null);
        
        int cdId = -1;
        CD cd; //create an instance of the CD class
        
        //cycle through each row of data
  while(cdCursor.moveToNext())
  {
   cdId = cdCursor.getInt(0);
     
   if(cdId != -1)
   {
    //if there are cds add the title and artist to the object
    cd = new CD(cdId, cdCursor.getString(1), cdCursor.getString(2));
    
    //add the tracks
    Cursor trackCursor = db.query(SQLHelper.TRACK_TABLE, 
            new String[] {SQLHelper.TRACK_TITLE}, SQLHelper.CD_ID + " = " + cdId, 
            null, null, null, null);
    
          //cycle through each row
    while(trackCursor.moveToNext())
    {
     cd.AddTracks(trackCursor.getString(0));
    }
    
    cds.add(cd); //add the CD to a list of Cds
   }
  }
  
  if (cds.size() > 0) 
  {
   //add the cds to the list view
   CdAdapter cdAdapter = new CdAdapter(this, R.layout.cd_row, cds);
   cdListView.setAdapter(cdAdapter);
   
   //each time a cd row is clicked we will bring up the CDDetail activity
   //to see all of the CD data
   cdListView.setOnItemClickListener(new PatientItemClickListener());
  }
 }
     
 //set up the add record label to be underlined
    private void initAddRecordTextView()
    {
     String addRecordText = this.getString(R.string.add_record);
     SpannableString contentUnderline = new SpannableString(addRecordText);
     contentUnderline.setSpan(new UnderlineSpan(), 0, contentUnderline.length(), 0);
     
     TextView addRecordTV = (TextView)findViewById(R.id.txtView_addRecord);
     addRecordTV.setText(contentUnderline);
     
     addRecordTV.setOnClickListener(new AddRecordListener());
    }
    
    /*
     * when the Add Record link is clcked then go to the add patient screen
     */
    private class AddRecordListener implements View.OnClickListener
    {

  @Override
  public void onClick(View v)
  {
   startActivity(new Intent(DatabaseTestActivity.this, AddRecordActivity.class));
  }
     
    }
    
    /*
     * Adds each CD from the array of patients into the adapter. 
     * Applyng the Cd_row layout file to each of them
     */
    private class CdAdapter extends ArrayAdapter 
    {
     public CdAdapter(Context context, int textViewResourceId, ArrayList cds) 
     {
   super(context, textViewResourceId, cds);
  }
     
     @Override
  public View getView(int position, View convertView, ViewGroup parent) 
     {
      if (convertView == null) 
      {
    LayoutInflater mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    convertView = mInflater.inflate(R.layout.cd_row, null);
   }
      
      final CD cd = getItem(position);
      
      if(cd != null)
      {
       TextView nameTV = (TextView) convertView.findViewById(R.id.TextView_Name);
       nameTV.setText(cd.getCdTitle());
      }
      
      return convertView;
     }
    }
    

In addition there is an ActionListener which bundles of all the content of cd that is clicked on and opens the detail view


private class PatientItemClickListener implements OnItemClickListener
    {

  @Override
  public void onItemClick(AdapterView adapter, View view, int position,long id)
  {
   CD cd = cds.get(position);
   Intent cdIntent = new Intent(DatabaseTestActivity.this, CDDetail.class);
   cdIntent.putExtra("cdId", cd.getID());
   cdIntent.putExtra("cdTitle", cd.getCdTitle());
   cdIntent.putExtra("cdArtist", cd.getCdArtist());
   cdIntent.putExtra("cdTracks", cd.getTracks());
   
   startActivity(cdIntent);
  }
     
    }

in the detail view we take the CD object that was sent across in the bundle and display the information


import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class CDDetail extends Activity {
 /*
  * This class takes a cd sent from the main
  * activity and displays all its data
  */
 
 private int cdId;
 private String title;
 private String artist;
 private String tracks;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.cd_detail);
  
  Bundle extra = getIntent().getExtras();
  initFormData(extra);
 }
 private void initFormData(Bundle extra)
 {
  if (extra != null) 
  { 
   cdId = extra.getInt("cdId");
      title = extra.getString("cdTitle");
      artist = extra.getString("cdArtist");
      
      tracks = extra.getString("cdTracks");
   
   
      initView(title, R.id.textView_cdTitle);
   initView(artist, R.id.textView_cdArtist);
   initView(tracks, R.id.textView_cdTracks);
  }
 }
 
 /*
  * Initilaize a text view with the data
  */
 private void initView(String patientData, int textViewName)
 {
  TextView PatientDataTV = (TextView)findViewById(textViewName);
  PatientDataTV.setText(patientData);
 }

}

Finally we will look at the Input form. Here is the code that inserts into the database


package com.spconger.databasetest;


import android.app.Activity;
import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class AddRecordActivity extends Activity{

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.add_record_layout);
  
  Button saveButton = (Button)findViewById(R.id.button1);
  saveButton.setOnClickListener(new SaveClickListener());
  
 }
 private class SaveClickListener implements View.OnClickListener
    {
     public void onClick(View v) 
     { 
      String cdTitle = showHideNameError(R.id.editTextTitle, R.id.title_error);
      String artist = showHideNameError(R.id.editTextArtist, R.id.artist_error);
      
         if( cdTitle == null || artist == null)
         {
          Toast errorEntry = Toast.makeText(AddRecordActivity.this, 
            "Settings were entered incorectly", Toast.LENGTH_LONG);
          errorEntry.show();
         }
         else
         {
          SQLHelper sqlHelper = new SQLHelper(AddRecordActivity.this);
          SQLiteDatabase db = sqlHelper.getWritableDatabase();
          
          long cdId = addCDToDB(sqlHelper, db, cdTitle, artist);
          
                if( cdId != -1)
                {
                 if(addAlergiesToDB(sqlHelper, db, cdId))
                 {
                  Toast successEntry = Toast.makeText(AddRecordActivity.this, 
              "CD successfully added", Toast.LENGTH_LONG);
            successEntry.show();
                 }
                }
               
         }
        }
    }
  
 /*
  * Will test if the entry is empty
  * if so it will display an error and if not it will clear the error
  */
 private String showHideNameError(int editTextId, int errorTextViewId)
    {
     EditText nameBox = (EditText)findViewById(editTextId);
     String name = nameBox.getText().toString().trim();
     
     TextView nameError = (TextView)findViewById(errorTextViewId);
     
     if(name.length() <= 0)
     {
      /* show error if the name isn't at least 3 characters */
      nameError.setText(R.string.error_blank);
      return null;
     }
     else
     {
      /* clear error if the name isn't at least 3 characters */
      nameError.setText("");
      return name;
     } 
    }
 
 
 /*
  * Adds the specified patient to the database
  * returns the patient id if the entry was entered correctly
  * returns -1 if the patient wasn't successfully entered into the db
  */
 private long addCDToDB(SQLHelper sqlHelper, SQLiteDatabase db, String title, String artist)
 {
  ContentValues values = new ContentValues();
        values.put(SQLHelper.CD_TITLE, title);
        values.put(SQLHelper.CD_ARTIST, artist);
        
        long cdId = db.insert(SQLHelper.CD_TABLE, null, values);
        
        if(cdId == -1)
        {   
         Toast toast = Toast.makeText(AddRecordActivity.this, "Error adding user to db" , Toast.LENGTH_LONG);
            toast.show();
            sqlHelper.close();
            return -1;
        }
        
        return cdId;
 }
 
 /*
  * Splits up the Tracs each one having it's own line,
  * then adds each entry to the db
  * returns true if they were successfully entered and false otherwise
  */
 private boolean addAlergiesToDB(SQLHelper sqlHelper, SQLiteDatabase db, long cdId)
 {
  ContentValues values = new ContentValues();
  
  EditText trackBox = (EditText)findViewById(R.id.editTextTracks);
  String trackText = trackBox.getText().toString().trim();
  
  if(trackText == "")
  {
   return true; //successfully added nothing
  }
  
  String[] trackItems = trackText.split("\n");
  
  for(int i= 0 ; i<trackItems.length; i++)
  {
   values.put(SQLHelper.CD_ID, cdId);
         values.put(SQLHelper.TRACK_TITLE, trackItems[i]);
         long id = db.insert(SQLHelper.TRACK_TABLE, null, values);
         
         if(id == -1)
         {
          Toast toast = Toast.makeText(AddRecordActivity.this, "Failure during insert", Toast.LENGTH_LONG);
             toast.show();
             return false;
         }
  }
  
  return true;
 }
}

No comments:

Post a Comment