Step 5: Database Integration

SQLite

As our last step, we'll be making adding database support in order to populate the text below our send button with information regarding the last Sup you sent. We will be using SQLite to store the last recipient's contract information.

More about Databases →

Configure the TextView

First, we have to configure our TextView to properly display our last sup sent in the format we previously established in our strings.xml.

Update our emptyLatestSup string in res/values/strings.xml and replace the todo with with "No sups sent recently."

Next, we will add an OnClickListener to mLastSupSent. Add the following fields to the top of our SupFragment.java

private String mLastSupSentFormat;
private String mSupDateFormat;

Next, add the following to our onCreateView() below our reference to mLastSupSent.

mSupDateFormat = getString(R.string.dateFormat);
mLastSupSentFormat = getString(R.string.latestSupFormat);
String lastSupText = SupDao.get(getContext()).getLatestSup(mLastSupSentFormat, mSupDateFormat);
if (lastSupText == null) {
    lastSupText = getString(R.string.emptyLatestSup);
}
mLastSupSent.setText(lastSupText);

We use formatted strings for the message and the date displayed in our TextView. The class we are currently missing, SupDao (Dao meaning Data Access Object), will be responsible for saving and retrieving the information regarding our last Sup that was sent. We'll be adding this shortly, but first we will be writing the rest of the necessary code for SQLite in SupFragment.java.

In our sendSup() method, add the following two calls in our finally block.

saveSup();
setLatestSup();

Now let's define these methods. Add these to SupFragment.java.

private void saveSup() {
    Sup sup = new Sup(mFriend, new Date());
    SupDao.get(getContext()).addSup(sup);
}

private void setLatestSup() {
    String lastSupText = SupDao.get(getContext()).getLatestSup(mLastSupSentFormat, mSupDateFormat);
    if (lastSupText == null) {
        lastSupText = getString(R.string.emptyLatestSup);
    }
    mLastSupSent.setText(lastSupText);
}

saveSup() creates an instance of the class Sup which we will implement next. This instance is saved to our SQLite database. setLatestSup() retrieves the String to display, constructed from the latest Sup saved in the database, from SupDao and sets the text in our TextView.

Sup

Next we need to create a model object which will be saved into our database. Create a new class called Sup in com.uci.android101.sup and use the following:

public class Sup {

    private UUID mId;
    private Friend mFriend;
    private Date mDate;

    public Sup(Friend friend, Date date) {
        this.mId = UUID.randomUUID();
        this.mFriend = friend;
        this.mDate = date;
    }

    public UUID getId() {
        return mId;
    }

    public Friend getFriend() {
        return mFriend;
    }

    public void setFriend(Friend friend) {
        this.mFriend = friend;
    }

    public Date getDate() {
        return mDate;
    }

    public void setDate(Date date) {
        this.mDate = date;
    }

}

Sup Schema

Now we have to define a schema for our database. Create a new subfolder, com.uci.android101.sup.database, and create a class in this folder called SupDbSchema. The contents of our schema class should be as follows:

public class SupDbSchema {

    public static final class SupTable {

        public static final String NAME = "sups";

        public static final class Cols {
            public static final String UUID = "uuid";
            public static final String NAME = "name";
            public static final String DATE = "date";
        }
    }
    
}

SQLiteOpenHelper

Android provides the SQLiteOpenHelper class to handle database creation and maintenance. Create a class in our database package that subclasses SQLiteOpenHelper called SupBaseHelper.

public class SupBaseHelper extends SQLiteOpenHelper {

    public static final int VERSION = 1;
    public static final String DATABASE_NAME = "supBase.db";
    
    public SupBaseHelper(Context context) {
        super(context, DATABASE_NAME, null, VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("create table " + SupDbSchema.SupTable.NAME + "(" +
            " _id integer primary key autoincrement, " +
            SupDbSchema.SupTable.Cols.UUID + ", " +
            SupDbSchema.SupTable.Cols.NAME + ", " +
            SupDbSchema.SupTable.Cols.DATE + ")");
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        return;
    }
}

SupDao

Lastly we need to create SupDao, our data access object, in com.uci.android101.sup.

public class SupDao {

    private static SupDao sSupDao;
    private SQLiteDatabase mDatabase;

    public static SupDao get(Context context) {
        if (sSupDao == null) {
            sSupDao = new SupDao(context);
        }
        return sSupDao;
    }

    private SupDao(Context context) {
        mDatabase = new SupBaseHelper(context.getApplicationContext()).getWritableDatabase();
    }

    public void addSup(Sup sup) {
        ContentValues values = getContentValues(sup);
        mDatabase.insert(SupDbSchema.SupTable.NAME, null, values);
    }

    public String getLatestSup(String latestSupFormat, String dateFormat) {
        SupCursorWrapper cursor = querySups();
        try {
            if (cursor.getCount() == 0) {
                return null;
            }
            cursor.moveToFirst();
            return cursor.getLatestSup(latestSupFormat, dateFormat);
        } finally {
            cursor.close();
        }
    }

    private SupCursorWrapper querySups() {
        Cursor cursor = mDatabase.query(
                SupDbSchema.SupTable.NAME,
                null,
                null,
                null,
                null,
                null,
                SupDbSchema.SupTable.Cols.DATE + " DESC",
                "1"
        );
        return new SupCursorWrapper(cursor);
    }

    private static ContentValues getContentValues(Sup sup) {
        ContentValues values = new ContentValues();
        values.put(SupDbSchema.SupTable.Cols.UUID, sup.getId().toString());
        values.put(SupDbSchema.SupTable.Cols.NAME, sup.getFriend().getFriendName());
        values.put(SupDbSchema.SupTable.Cols.DATE, sup.getDate().getTime());
        return values;
    }

    private class SupCursorWrapper extends CursorWrapper {
        public SupCursorWrapper(Cursor cursor) {
            super(cursor);
        }

        public String getLatestSup(String latestSupFormat, String dateFormat) {
            DateTime dateTime = new DateTime(getLong(getColumnIndex(SupDbSchema.SupTable.Cols.DATE)));
            DateTimeFormatter fmt = DateTimeFormat.forPattern(dateFormat);
            String dateString = fmt.print(dateTime);
            String friendName = getString(getColumnIndex(SupDbSchema.SupTable.Cols.NAME));
            return String.format(latestSupFormat, friendName, dateString);
        }
    }

}

You may notice that you have errors for our new datetime classes. This is because we need to add another library dependency, like some may have done in Step 2. Add the following dependency and then resolve all of your imports.

Now, run your app and send some sups! Your last sup sent field should properly display the information of when and to whom the last sup was sent.