sqlite

43
SQLite Android Application Development

Upload: youssef-addi

Post on 18-Dec-2015

16 views

Category:

Documents


2 download

DESCRIPTION

SQLite

TRANSCRIPT

  • SQLiteAndroid Application Development

  • By creating the SQLiteScores app, you will gain experience with ... Writing a DatabaseAdapter Extending the DatabaseOpenHelper class Cursors and CursorAdapters ContentValues CRUD

    https://github.com/AndroidCourseMaterial/SQLiteScoreshttps://github.com/AndroidCourseMaterial/SQLiteScores_Solution

  • SQLite is a relational database system

    Stores data in tables.

    Visual representation of a SQLite table:

    The right way to do data storage on mobile devices!For media, just stores URI's of the files

    _id name score

    0 Dave 95

    1 Jimmy 100

    2 Dr. B 75

    3 Stokes 98

  • Main concepts: ContentValues and Cursors

    ContentValues: a single row in a Table. Maps column names to values.put(key, value)

    Cursor: a pointer to a result set returned by a QueryIs iterable: while (cursor.moveToNext()) {...}

    _id name score

    0 Dave 67

    1 Jimmy 100

    2 Dr. B 95

    3 Stokes 98

    ContentValues

  • Main concepts: ContentValues and Cursors

    ContentValues: a single row in a Table. Maps column names to values

    Cursor: a pointer to a result set returned by a QueryIs iterable: while (cursor.moveToNext()) {...}Also: .moveToFirst, .getColumnIndex, .getString, ...

    _id name score

    0 Dave 67

    1 Jimmy 100

    2 Dr. B 95

    3 Stokes 98

    Cursor on query, Get all entries with score > 80

  • Download or git clone the starting code

    SQLiteScoreshttps://github.com/AndroidCourseMaterial/SQLiteScores

    I recommend changing the SDK to 4.0+ and making sure the Java compiler compliance level is 1.6:

    Right-click project > Properties > Android | Java CompilerChange the version in the Manifest to SDK 11+You may also need to clean and rebuild the projectRun it to see what you have!

    Github download instructions

  • Add some names and scores, then edit and delete scoresGood... Menu, dialogs, and view adapter work

    Bad... Old-style dialogsNo storage

  • Score.java

    Basic Java model object

    Variable Type DescriptionmName String Stores the name of a personmScore int Stores the score that person got

  • SQLiteScoreAdapter.java

    Placeholder to interact with SQLite database SQLiteOpenHelper subclass to open/close database CRUD convenience methods for Scores

    Create: Add a score to the SQLite database Read: Get a score from the SQLite database Update: Edit a score in the SQLite database Delete: Remove a score from the SQLite database

    Currently holds just a few basic constants.

    Score Instance

    SQLite Table Row

  • ScoresListActivity.java

    ListActivity ListView + ArrayAdapter + ArrayList

    OnItemClick listener to Edit a score Options menu

    Add score Context menu

    Delete scoreEdit score

    CRUD stubs (to be replaced) Dialog

    Add a new scoreUpdate an existing score

  • Take a step of faith: remove the arrays

    Delete or comment out the array and adapter:// private ArrayList mScores = new ArrayList();// private ArrayAdapter mScoreAdapter;

    Comment out the CRUD until it compiles again. For example:private void addScore(Score s) {

    // mScores.add(s);// Collections.sort(mScores);// mScoreAdapter.notifyDataSetChanged();

    }

    private Score getScore(long id) {// return mScores.get((int) id);return null ;

    } Now it's REALLY broken!

  • We need some boilerplate code in two classes to set up the database

    ScoreListActivityCRUD, keys

    ScoreDataAdapter create, upgrade, returns database

    SQLiteOpenHelper subclass SQLiteDatabase

  • Add instance variables to prepare for the database

  • Code from the top down: call some methods you'll write next

  • Stub in methods in ScoreDataAdapter.java

    public ScoreDataAdapter(Context context) {// Create a SQLiteOpenHelper

    }

    public void open() {// Open the database

    }

    public void close() {// Close the database

    }

  • Member variables

    private SQLiteOpenHelper mOpenHelper; private SQLiteDatabase mDb;

    SQLiteOpenHelper - Opening a SQLite database involves a lot of steps that are always the same (mostly the same). So Android has a class that does all the identical work. You will need to customize it for your needs.

    SQLiteDatabase - The actual database: SQLite table(s)

  • Create a nested class: ScoreDbHelper

  • Define the adapter functions in terms of the database and helper

    They don't do much until you finish the ScoreDbHelper inner class

  • Defining your columns

    _id is always recommendedname and score

    _id name score

    0 Dave 67

    1 Jimmy 100

    2 Dr. B 95

    3 Stokes 98

  • Add a member variable in the Score

    public class Score implements Comparable{

    private String mName;

    private int mScore;

    private long mId;

    public long getId() { return mId; }

    public void setId(int id) { mId = id; }

    public String getName() { return mName; }

    public void setName(String name) { mName = name; }

    public int getScore() { return mScore; }

    public void setScore(int score) { mScore = score; }

    public int compareTo(Score other) { return other.getScore() - getScore(); }

    public String toString() { return getName() + " " + getScore(); }

    }

  • Create SQLiteScoreAdapter constants for each table column

    Add below the DATABASE_VERSION constant.

  • Here are the only SQL statements you'll write

    Use these when you create and upgrade (delete and re-create) your database in the helper

  • Execute the SQL in the helper's onCreate and onUpgrade methods

    @Override

    public void onCreate(SQLiteDatabase db) {db.execSQL(CREATE_STATEMENT);

    }

    @Override

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    Log.d(TAG, "Updating from version " + oldVersion + " to " + newVersion + ", which will destroy old table(s).");

    db.execSQL(DROP_STATEMENT);onCreate(db);

    }

  • Backing up the CRUD methods

    Time for the Magic

  • // Convert from score object to a table rowprivate ContentValues getContentValuesFromScore(Score score) {

    ContentValues rowValues = new ContentValues();rowValues.put(KEY_NAME, score.getName());rowValues.put(KEY_SCORE, score.getScore());return rowValues;

    }

    /**

    * Add score to the table. If is successful,

    * return the new id for that Score, otherwise return -1.

    *

    * @param score

    * @return id of the inserted row or -1 if failed

    */public long addScore(Score score) {

    ContentValues rowValues = getContentValuesFromScore(score);return mDb.insert(TABLE_NAME, null, rowValues);

    }

    Adding a row, returning it with id

    These go into the ScoreDataAdapter class below the open() and close() methods

  • Rewrite CRUD's addScore to use the dbAdapter

    private void addScore(Score s) {// mScores.add(s);// Collections.sort(mScores);// mScoreAdapter.notifyDataSetChanged();mScoreDataAdapter.addScore(s);

    }

    Adding is now ready! But we need to see the data.

  • We need to read all data in the table to update our view

    Back in the ScoreDataAdapter

    public Cursor getScoresCursor() {String[] projection = new String[] { KEY_ID, KEY_NAME, KEY_SCORE };return mDb.query( TABLE_NAME, projection, null, null, null, null, KEY_SCORE + " DESC");

    }query(tableName, list of columns, where clause, where params for wildcards,group by, having, order, max rows)

    The order of the cursor is setup as scores in decreasing order

  • Replace the ArrayAdapter with a SimpleCursorAdapter in the ListActivity

    @Override

    public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout. scores_list_activity);

    mScoreDataAdapter = new SQLiteScoreAdapter(this);mScoreDataAdapter.open();

    int viewResourceId = R.layout.score_list_item;

    Cursor cursor = mScoreDataAdapter.getScoresCursor();String[] fromColumns = new String[] { ScoreDataAdapter.KEY_NAME,

    ScoreDataAdapter.KEY_SCORE };int[] toTextViews = new int[] { R.id.textViewName, R.id.textViewScore};

    mCursorAdapter = new SimpleCursorAdapter(this, viewResourceId, cursor, fromColumns, toTextViews, 0);

    setListAdapter(mCursorAdapter);registerForContextMenu(getListView());

    }

  • We can see stuff!

    And the values persist!Hit home and then come back (or rotate)

  • To get an immediate result when you add, you need to reload the cursorprivate void addScore(Score s) {

    // mScores.add(s);// Collections.sort(mScores);// mScoreAdapter.notifyDataSetChanged();mScoreDataAdapter.addScore(s);Cursor cursor = mScoreDataAdapter.getScoresCursor();mCursorAdapter.changeCursor(cursor);

    }

  • Adding the remaining CRUD

    CRUD ScoresListActivity ScoreDataAdapter

    Create addScore (done) addScore (done)

    Read getScore getScoresCursor (done)getScore

    Update editScore updateScore

    Delete removeScore removeScore

  • Updating the fields in the dialog edits

    Adding new scores works. What about editing an existing score? First we just need to autofill the dialog with getS

  • ScoreDataAdapter: Get a single row in the table

    public Score getScore(long id) {

    // Getting a cursor for the specific idString[] projection = new String[] { KEY_ID, KEY_NAME, KEY_SCORE };String selection = KEY_ID + "=" + id;Cursor c = mDb.query(true, TABLE_NAME, projection, selection,

    null,null,null,null,null);

    // Using the cursor to get values from the tableif(c != null && c.moveToFirst()) {

    Score s = new Score();int idColumn = c.getColumnIndexOrThrow(KEY_ID);int nameColumn = c.getColumnIndexOrThrow(KEY_NAME);int scoreColumn = c.getColumnIndexOrThrow(KEY_SCORE);s.setID(c.getInt(idColumn));s.setName(c.getString(nameColumn));s.setScore(c.getInt(scoreColumn));return s;

    }return null;

    }

    Get a distinct Cursor (one value)

  • ScoresListActivity

    private Score getScore(long id) {// return mScores.get((int) id);return mScoreDataAdapter.getScore(id);

    }

    Now the edit dialog box should auto fill correctly. It just won't update the table. :)

  • ScoreDataAdapter updateScore

    public void updateScore(Score score) {ContentValues rowValues = getContentValuesFromScore(score);

    String whereClause = KEY_ID + "=" + score.getID();mDb.update(TABLE_NAME, rowValues, whereClause, null);

    }

  • ScoresListActivity

    private void editScore(Score s) {if (mSelectedId == NO_ID_SELECTED) {

    Log.e(TAG, "Attempt to update with no score selected.");}

    s.setID((int) mSelectedId);mScoreDataAdapter.updateScore(s);Cursor cursor = mScoreDataAdapter.getScoresCursor();mCursorAdapter.changeCursor(cursor);

    }

  • Edits done, only delete remains

    Edits should actually update the database now

  • ScoreDataAdapter removeScore

    public boolean removeScore(long id) {return mDb.delete(TABLE_NAME, KEY_ID + "=" + id, null) > 0;

    }

    public boolean removeScore(Score s) {return removeScore(s.getID());

    }

  • ScoresListActivity

    private void removeScore(long id) {// mScores.remove((int)id);// Collections.sort(mScores);// mScoreAdapter.notifyDataSetChanged();

    mScoreDataAdapter.removeScore(id);Cursor cursor = mScoreDataAdapter.getScoresCursor();mCursorAdapter.changeCursor(cursor);

    }

  • Delete. That's all four CRUD methods

    Long press a row then select Delete

  • SQLiteScores

  • Subtle but HUGE

    It might not have felt like a huge difference from the starting app to the end, but we assure you it was.

    Data Persistence is an invaluable skill in your bag of tricks

    But there is more! Content Providers are an interface that ......lets you share your data with other apps...allows you to use data from other apps

    Contacts, media, calendars, 3rd party apps

  • SQL Editors (require root access)

    Copy database from rooted phone to laptop to view:SQLite Browser Database (free)

    http://sourceforge.net/projects/sqlitebrowser/

    View directly on phone:SQLite Editor by Speed Software ($2.99)

    https://play.google.com/store/apps/details?id=com.speedsoftware.sqleditor&hl=en

    Worth every penny if your phone is rooted