s12.androidcookbook.steele.ch9.sqlite

Upload: dumitru-adrian-iulian

Post on 02-Jun-2018

225 views

Category:

Documents


0 download

TRANSCRIPT

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    1/12

    232 Chapter 9 Data Storage Methods

    Then, any application can automatically have the EULA functionality by simply putting

    the following line in the onCreate()method of the main activity of the application:

    Eula.show(this);

    SQLite DatabaseFor more complex data structures, a database provides a quicker and more flexible access

    method than flat files or shared preferences.Android provides a built-in database called

    SQLite that provides full relational database capability utilizing SQL commands. Each

    application that uses SQLite has its own instance of the database, which is by default

    accessible only from the application itself.The database is stored in the /data/data/

    /databases folder of an Android device.A Content Provider can be

    used to share the database information between applications.The different steps for utiliz-

    ing SQLite are

    1. Create a database.

    2. Open the database.

    3. Create a table.

    4. Create an insert interface for datasets.

    5. Create a query interface for datasets.

    6. Close the database.

    The next recipe provides a general method to accomplish these steps.

    Recipe: Creating a Separate Database Package

    A good modular structure to classes is essential for more complicated Android projects.

    Here, the database class is put in its own package com.cookbook.data so it is easy to

    reuse.This package contains three classes: MyDB, MyDBhelper, and Constants.

    The MyDB class is shown in Listing 9.9. It contains a SQLiteDatabaseinstance and a

    MyDBhelperclass (described in the following) with the methods that follow:

    n MyDB()Initializes a MyDBhelper instance (the constructor).

    n open()Initializes a

    SQLiteDatabaseinstance using the

    MyDBhelper.This opens awriteable database connection. If SQLite throws any exception, it tries to get a

    readable database instead.

    n close()Closes the database connection.

    n insertdiary()Saves a diary entry to the database as name-value pairs in a

    ContentValues instance, and then passes the data to the SQLitedatabaseinstance

    to do an insert.

    Download at www.wowebook.co

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    2/12

    233SQLite Database

    n getdiaries()Reads the diary entries from the database, saves them in a Cursor

    class, and returns it from the method.

    Listing 9.9 src/com/cookbook/data/MyDB.java

    package com.cookbook.data;

    import android.content.ContentValues;

    import android.content.Context;

    import android.database.Cursor;

    import android.database.sqlite.SQLiteDatabase;

    import android.database.sqlite.SQLiteException;

    import android.util.Log;

    public class MyDB {

    private SQLiteDatabase db;

    private final Context context;

    private final MyDBhelper dbhelper;

    public MyDB(Context c){

    context = c;

    dbhelper = new MyDBhelper(context, Constants.DATABASE_NAME, null,

    Constants.DATABASE_VERSION);

    }

    public void close()

    {

    db.close();

    }

    public void open() throws SQLiteException

    {

    try {

    db = dbhelper.getWritableDatabase();

    } catch(SQLiteException ex) {

    Log.v("Open database exception caught", ex.getMessage());

    db = dbhelper.getReadableDatabase();

    }

    }

    public long insertdiary(String title, String content)

    {

    try{ContentValues newTaskValue = new ContentValues();

    newTaskValue.put(Constants.TITLE_NAME, title);

    newTaskValue.put(Constants.CONTENT_NAME, content);

    newTaskValue.put(Constants.DATE_NAME,

    java.lang.System.currentTimeMillis());

    return db.insert(Constants.TABLE_NAME, null, newTaskValue);

    } catch(SQLiteException ex) {

    Download at www.wowebook.co

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    3/12

    234 Chapter 9 Data Storage Methods

    Log.v("Insert into database exception caught",

    ex.getMessage());

    return -1;

    }

    }

    public Cursor getdiaries()

    {

    Cursor c = db.query(Constants.TABLE_NAME, null, null,

    null, null, null, null);

    return c;

    }

    }

    The MyDBhelperclass extends SQLiteOpenHelperand is shown in Listing 9.10.The

    SQLiteOpenHelperframework provides methods to manage database creation and

    upgrades.The database is initialized in the class constructor MyDBhelper().This requiresthe context and database name to be specified for creation of the database file under

    /data/data/com.cookbook.datastorage/databases and database schema version to

    determine whether the onCreate()or onUpgrade() method is called.

    Tables can be added in the onCreate()method using a custom SQL command such as:

    create table MyTable (key_id integer primary key autoincrement,

    title text not null, content text not null,

    recorddate long);

    Whenever a database needs to be upgraded (when a user downloads a new version of an

    application, for example), the change in database version number calls the onUpgrade()

    method.This can be used to alter or drop tables as needed to update the tables to the newschema.

    Listing 9.10 src/com/cookbook/data/MyDBhelper.java

    package com.cookbook.data;

    import android.content.Context;

    import android.database.sqlite.SQLiteDatabase;

    import android.database.sqlite.SQLiteException;

    import android.database.sqlite.SQLiteOpenHelper;

    import android.database.sqlite.SQLiteDatabase.CursorFactory;

    import android.util.Log;

    public class MyDBhelper extends SQLiteOpenHelper{

    private static final String CREATE_TABLE="create table "+

    Constants.TABLE_NAME+" ("+

    Constants.KEY_ID+" integer primary key autoincrement, "+

    Constants.TITLE_NAME+" text not null, "+

    Constants.CONTENT_NAME+" text not null, "+

    Constants.DATE_NAME+" long);";

    Download at www.wowebook.co

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    4/12

    235SQLite Database

    public MyDBhelper(Context context, String name, CursorFactory factory,

    int version) {

    super(context, name, factory, version);

    }

    @Override

    public void onCreate(SQLiteDatabase db) {

    Log.v("MyDBhelper onCreate","Creating all the tables");

    try {

    db.execSQL(CREATE_TABLE);

    } catch(SQLiteException ex) {

    Log.v("Create table exception", ex.getMessage());

    }

    }

    @Override

    public void onUpgrade(SQLiteDatabase db, int oldVersion,

    int newVersion) {

    Log.w("TaskDBAdapter", "Upgrading from version "+oldVersion

    +" to "+newVersion

    +", which will destroy all old data");

    db.execSQL("drop table if exists "+Constants.TABLE_NAME);

    onCreate(db);

    }

    }

    The third file of the com.cookbook.data package is the Constants class shown inListing 9.11.This class is used to hold all the String constants because they are utilized in

    both MyDB and MyDBhelper.

    Listing 9.11 src/com/cookbook/data/Constants.java

    package com.cookbook.data;

    public class Constants {

    public static final String DATABASE_NAME="datastorage";

    public static final int DATABASE_VERSION=1;

    public static final String TABLE_NAME="diaries";

    public static final String TITLE_NAME="title";

    public static final String CONTENT_NAME="content";

    public static final String DATE_NAME="recorddate";

    public static final String KEY_ID="_id";

    }

    Download at www.wowebook.co

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    5/12

    236 Chapter 9 Data Storage Methods

    Recipe: Using a Separate Database Package

    This recipe demonstrates SQLite data storage utilizing the previous recipes database

    package. It also ties together the login screen from the Changing the UI Based on Stored

    Data recipe and enables the creation and listing of personal diary entries. First, a layout

    XML file for creating diary entriesdiary.xmlis shown in Listing 9.12 with its output

    screen shown in Figure 9.3.

    Listing 9.12 res/layout/diary.xml

    Download at www.wowebook.co

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    6/12

    237SQLite Database

    Figure 9.3 The diary entry creation screen.

    The main activity is Diary.java, shown in Listing 9.13.The com.cookbook.datapackage

    needs to be imported,and the MyDB object is declared,initialized,and opened for use.It also

    displays the diary.xml layout and handles the submit button press to save data to the database.

    Listing 9.13 src/com/cookbook/datastorage/Diary.java

    package com.cookbook.datastorage;

    import android.app.Activity;

    import android.content.Intent;

    import android.os.Bundle;

    import android.view.View;

    import android.view.View.OnClickListener;

    import android.widget.Button;

    import android.widget.EditText;

    import com.cookbook.data.MyDB;

    public class Diary extends Activity {

    EditText titleET, contentET;

    Button submitBT;

    MyDB dba;

    @Override

    public void onCreate(Bundle savedInstanceState) {

    Download at www.wowebook.co

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    7/12

    238 Chapter 9 Data Storage Methods

    super.onCreate(savedInstanceState);

    setContentView(R.layout.diary);

    dba = new MyDB(this);

    dba.open();

    titleET = (EditText)findViewById(R.id.diarydescriptionText);

    contentET = (EditText)findViewById(R.id.diarycontentText);

    submitBT = (Button)findViewById(R.id.submitButton);

    submitBT.setOnClickListener(new OnClickListener() {

    public void onClick(View v) {

    try {

    saveItToDB();

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    });

    }

    public void saveItToDB() {

    dba.insertdiary(titleET.getText().toString(),

    contentET.getText().toString());

    dba.close();

    titleET.setText("");

    contentET.setText("");

    Intent i = new Intent(Diary.this, DisplayDiaries.class);

    startActivity(i);

    }

    }

    The DataStorage.java class is the same as in Listing 9.6 with the MyPreferences.class

    changed to launch the Diary.class when the login is successful:

    Toast.makeText(DataStorage.this, "login passed!!",

    Toast.LENGTH_SHORT).show();

    Intent i = new Intent(DataStorage.this, Diary.class);

    startActivity(i);

    Finally, the AndroidManifest XML file must be updated to include the new activities, as

    shown in Listing 9.14.

    Listing 9.14 AndroidManifest.xml

    Download at www.wowebook.co

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    8/12

    239SQLite Database

    Now that a separate database has been integrated, the layout for the list of entries is dis-

    cussed in the next recipe to complete the diary application.

    Recipe: Creating a Personal Diary

    This recipe leverages the ListView object to display multiple entries from a SQLite data-

    base table. It shows these items in a vertically scrolling list.The ListView needs a data

    adapter to tell the View whenever the underlying data changes.Two XML files need to be

    created:diaries.xml, which populates the ListView shown in Listing 9.15, and

    diaryrow.xml,which populates the row inside the ListView shown in Listing 9.16.

    Listing 9.15 res/layout/diaries.xml

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    9/12

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    10/12

    241SQLite Database

    import android.view.ViewGroup;

    import android.widget.BaseAdapter;

    import android.widget.TextView;

    import com.cookbook.data.Constants;

    import com.cookbook.data.MyDB;

    public class DisplayDiaries extends ListActivity {

    MyDB dba;

    DiaryAdapter myAdapter;

    private class MyDiary{

    public MyDiary(String t, String c, String r){

    title=t;

    content=c;

    recorddate=r;

    }

    public String title;public String content;

    public String recorddate;

    }

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    dba = new MyDB(this);

    dba.open();

    setContentView(R.layout.diaries);

    super.onCreate(savedInstanceState);

    myAdapter = new DiaryAdapter(this);this.setListAdapter(myAdapter);

    }

    private class DiaryAdapter extends BaseAdapter {

    private LayoutInflater mInflater;

    private ArrayList diaries;

    public DiaryAdapter(Context context) {

    mInflater = LayoutInflater.from(context);

    diaries = new ArrayList();

    getdata();

    }

    public void getdata(){

    Cursor c = dba.getdiaries();

    startManagingCursor(c);

    if(c.moveToFirst()){

    do{

    String title =

    c.getString(c.getColumnIndex(Constants.TITLE_NAME));

    Download at www.wowebook.co

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    11/12

    242 Chapter 9 Data Storage Methods

    String content =

    c.getString(c.getColumnIndex(Constants.CONTENT_NAME));

    DateFormat dateFormat =

    DateFormat.getDateTimeInstance();

    String datedata = dateFormat.format(new

    Date(c.getLong(c.getColumnIndex(

    Constants.DATE_NAME))).getTime());

    MyDiary temp = new MyDiary(title,content,datedata);

    diaries.add(temp);

    } while(c.moveToNext());

    }

    }

    @Override

    public int getCount() {return diaries.size();}

    public MyDiary getItem(int i) {return diaries.get(i);}

    public long getItemId(int i) {return i;}public View getView(int arg0, View arg1, ViewGroup arg2) {

    final ViewHolder holder;

    View v = arg1;

    if ((v == null) || (v.getTag() == null)) {

    v = mInflater.inflate(R.layout.diaryrow, null);

    holder = new ViewHolder();

    holder.mTitle = (TextView)v.findViewById(R.id.name);

    holder.mDate = (TextView)v.findViewById(R.id.datetext);

    v.setTag(holder);

    } else {

    holder = (ViewHolder) v.getTag();}

    holder.mdiary = getItem(arg0);

    holder.mTitle.setText(holder.mdiary.title);

    holder.mDate.setText(holder.mdiary.recorddate);

    v.setTag(holder);

    return v;

    }

    public class ViewHolder {

    MyDiary mdiary;

    TextView mTitle;

    TextView mDate;

    }

    }

    }

    Download at www.wowebook.co

  • 8/11/2019 s12.AndroidCookbook.steele.ch9.SQLite

    12/12

    243Content Provider

    Content ProviderEvery application has its own sandbox and cannot access data from other applications. If

    access to functions not provided by its own sandbox is required, the application mustexplicitly declare permission upfront before installation.Android provides an interface

    called ContentProviderto act as a bridge between applications, enabling them to share

    and change each others data.A content provider allows a clean separation between the

    application layer and data layer. It requires a permission setting in the AndroidManifest

    XML file and can be accessed using a simple URI model.

    Some native databases Android makes available as content providers are

    n BrowserRead or modify bookmarks, browser history, or web searches.

    n CallLogView or update the call history.

    n

    ContactsRetrieve, modify, or store the personal contacts. Contact information isstored in a three-tier data model of tables under a ContactsContractobject:

    n ContactsContract.DataContains all kinds of personal data.There is a

    predefined set of common data, such as phone numbers and email addresses,

    but the format of this table can be application-specific.

    n ContactsContract.RawContactsContains a set of Data objects associated

    with a single account or person.

    Figure 9.4 The ListView of diary entries.