sqlite
DESCRIPTION
SQLiteTRANSCRIPT
-
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