Wednesday, January 28, 2015

MyNotes: Updating the Database

I am going to keep my database schema the same.


I don't really like the names of the database, table, or columns.  However, I don't want to change the schema since the app has already been released and the schema will still work for the expected functionality.  It sucks, but that is one of the trade-offs that have to be made sometimes.

The same cannot be said for the code that defines and manages the database.  That is going to get a major overhaul.

Step 1: Updating the Common Library

My first order of business is create some classes in the CommonLibrary to help with future database needs.  The classes are :

  1. CommonTerms - An interface that defines common terms and phrases used to define and create database schemas. Basically, just a constants class.
  2. DatabaseModel - An interface that defines the common methods for defining and setting up a database.  This will let me use the DatabaseHelper for my database management.
  3. DatabaseHelper - A helper class to manage the databases for an app.
These classes are located under the com.fsk.common.database folder.  Take a peek at them when you have a chance to understand what they are.

Step 2: Adding the CommonLibrary Unit Tests

The first step here is to update the manifest to let me build an apk.  The library manifest suffers the same issue the MyNotes manifest has with respect to the duplicate file problem.  That was discussed briefly in the Setting Up the Unit Tests entry.

Basically, I just added the following entry to the Android block in the CommonLibary gradle file:

    //Required to prevent duplicate files during the build due to the imported libraries.
    packagingOptions {
        exclude 'LICENSE.txt'
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/dependencies.txt'
        exclude 'META-INF/LGPL2.1'
    }

I also added a block to the same gradle file to support java 7:

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }

Next, I created the first unit test for the DatabaseHelper file.  I don't need unit tests for the other two files so we can move onto the MyNotes module changes.

Step 3: Updating the MyNotes Module

These changes all resolve around removing or deprecating the old database code and replacing it with the new database setup.

In the original code, the database setup/management was messy and hard to follow because it was split between three main files: DatabaseKeys, NotesTableManager, and DatabaseManager.  Unfortunately, some of the Database management leaked into other classes, which I am going to deal with in the next entry.

For the new design, I moved the entire database schema into the MyNotesDatabaseModel class (com.fsk.mynotes.data.database).  This class implements the CommonLibrary's Database Interface so that I can just use the DatabaseHelper (or an extension of it) to manage my database setup and access.

The original code also has some issues with the timing and survival of the database.  Unfortunately, I created the database in the Activities which meant that sometimes the database went down and there was a lag between the activity starting and the database being ready.

This time around I want to centralize my database initialization into one area that will guarantee it stays alive for the entire application life cycle.  I also want to be sure it is alive before the first activity creates. Luckily, I can do this by creating a custom Application class : MyNotesApplication.

I have to modify the manifest to tell it to use the MyNotesApplication class instead of the system default one. this is done by adding the following line to the manifest application element :

<application
  android:name=".MyNotesApplication"
  android:label="@string/app_name"
  android:icon="@drawable/my_icon">
...
</application>

In MyNotesApplication, I extended the OnCreate method to create the database and initialize the DatabaseHelper with it.

My last step is to do a little cleanup and preparation for removing the NoteTableManager.  The NoteTableManager is going to be removed soon, but it is too big of task for this entry.  For now, I am just going to deprecate and modify it internally to use the DatabaseHelper.

Commits


That is it for this round of mods.  The commit can be found at https://github.com/fsk-software/mynotes/commit/9e368c82f2b5fc7291e2a48127e35ea1da26c7b5


*Technically, the code will run at this point, but it looks bad and is only semi-functional.  The next few sets of changes will probably render it inoperable for a while.

Wednesday, January 21, 2015

MyNotes: Creating the common library.

My first code change is to update the database.  The schema for the DB is okay, but the code could use a little work.  Since databases use a lot of common terms, this is a good opportunity to create some common classes that could be shared with other apps.  For now, I am just going to make this a separate module within my project.  Once I am happy with the module I may move it into its own repository in GitHub.

Step 1 : Create the Module

Creating a new module is pretty easy.  Just do File->New Module. In the dialog choose the library option:

On the next screen, just name your module and give it a package name:



In the next dialog select "No Activity" and press finish.  Once done it will construct the module, complete with the unit test directories for you.


If you haven't used a Library Module before, you will want to review the rules for library modules at the Android Development Blog.  In general, they are incredibly convenient and useful, but be sure to follow the rules for them.
I want my library project to use the same unit test framework as my main project so I am updating its gradle file to include Mockito and Hamcrest as well (See my previous blog entry for how to do that).

The library project comes with some extra stuff that I don't want so I am going to remove the following resources:

  • ic_launcher.png from the various drawable folders 
  • strings.xml from the values folder.
I also modified the CommonLibrary manifest.xml to remove the label and icon attributes from the application element.

The commit is at https://github.com/fsk-software/mynotes/commit/4002903759d580b380b588cf02b1fc146675c211

Step 3: Add the Library Module Dependency


The last step is to add a dependency between the MyNotes Module and the CommonLibrary module.  The steps are:
  1. File->Project Structure...
  2. Select the module that will receive the dependency (MyNotes)
  3. Open the Dependency Tab
  4. Click the green "+" sign
  5. Select "Module Dependency" and select the module (CommonLibrary)
It will look like this afterward:


This will automatically update the MyNotes modules build.gradle filewith the module dependency.

The commit is at https://github.com/fsk-software/mynotes/commit/a92ab9e9bb77d4c340f71e1c5e17a327f2c409eb






Wednesday, January 14, 2015

MyNotes: Setting up the Unit Test Framework

The next step is to set up the unit test framework for the project.  

There are a lot options for this but I prefer a very simple setup using only junit, mockito, and hamcrest.  Robolectric is also a great option and will dramatically speed up the tests.  However, I have had issues with it when mocking statics so I tend to stay away from it unless I think the slower speed of  running on an emulator will cause problems.

I start my setup by creating a sister folder to my main folder.  The new folder is named androidTest and will contain all of my unit tests.  Under  the androidTest folder,  I duplicate the same folder structure as my main folder.



Next we have to modify the gradle.build file in the MyNotes modules to add dependencies for the unit tests.

This can be tricky to get working correctly, but the setup that works for me is to add the following lines to the dependencies block:


    //Unit test dependencies
    androidTestCompile group: 'org.hamcrest', name: 'hamcrest-core', version: '1.3'
    androidTestCompile group: 'junit', name: 'junit-dep', version: '4.11'
    androidTestCompile("org.mockito:mockito-core:1.9.+") {
        exclude group: 'org.hamcrest'
    }

This will only include the hamcrest, junit and mockito libraries only when running the unit tests.
The junit and hamcrest inclusion will cause a duplicate file build error due to both libraries including a LICENSE.txt file.  This error (and many more like it) can be fixed by including the following block in the android section of the same gradle file:

packagingOptions {
        exclude 'LICENSE.txt'
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/dependencies.txt'
        exclude 'META-INF/LGPL2.1'
    }

 Now we just sync the gradle file and it should be ready to start writing unit tests.

The first test is really simple and mainly to test the unit test setup.  I named it NoteTest.java and it is located under androidTest/java/com/fsk/mynotes/data.

The class inherits off AndroidTestCase and only includes one test for now.  All of the test methods must start with "test" or have the @Test annotation :

package com.fsk.mynotes.data;

import android.test.AndroidTestCase;

/**
 * Test the {@link com.fsk.mynotes.data.Note class}.
 */
public class NoteTest extends AndroidTestCase {

    public void testNote() throws Exception {
        Note note = new Note(-1, null, 0, null);
        assertEquals(0, note.getColor());
        assertEquals(-1, note.getRow());
        assertEquals(null, note.getText());
    }
}

And of course the next step is to run the test.  Here are the steps to create the unit test run configuration in AndroidStudio:

  1. Run->Edit Configurations...
  2. Highlight Android Tests in the left menu
  3. Press the green + button
  4. Give the configuration a name.  In my case I called it "Test All".
  5. Select the module to test (MyNotes)
  6. Select the tests to run.  For this configuration, I want all tests to run.

My ending configuration looks like this:

You can also take a shortcut for individual test files:

  1. Select the test in the projects window
  2. Right click
  3. Select either "Run xxxx" or "Debug xxxx"
  4. Select the unit test configuration.  It is the one is the one with the little android icon.




Then just the run the configuration of your choice and watch the test results in the Studio:



Tada, it works!

The commit for the entry is https://github.com/fsk-software/mynotes/commit/f025e582c5dddc06fe9b746d194f52c7ad04d7aa

BTW: Git doesn't like committing empty directories, so I added a ".gitkeep" file into the empty directories for the commit.  The file will be removed later once I actually add content.

Wednesday, January 7, 2015

MyNotes: Organizing the Legacy Code

Now that everything is compiling again, I have a few choices on the next step. I can either rework the UI for the material design or I can start assessing the legacy code.

As you can tell from the title, I am starting with the code assessment.  Mostly, because I struggle with UI design and I can spend some time thinking about it and doing research while doing the code assessment.

The first step of the assessment is to organize the existing code.  This will force me to re-learn the architecture of the app and to make it easier to break down for test later on.   I already known that most of the code is going to completely overhauled, but I need to figure out what might be salvageable.

The legacy code base does not have any structure.  In some ways this make this easier since I don't have to remove any existing structure.

I am only grouping into rough categories right now.  I will refine and regroup the code as the refactoring process moves forward.  I am starting at the bottom grouping all of my database management code into a database package:

Next, I want to look for my data objects that are the accessors/modifiers for the database data.  In this case I only have one class, Note.  I am going to put this under a data package. Since I also consider the database to be data, I am going to move that package under data as well. This gives us this structure:

Since the bulk of the rest of the code is UI related classes, I am grouping these classes under a "presentation" folder.  Under that folder, I group the classes based on type.
I did a special grouping under components called "note_view".  This is because I tightly coupled the NoteView to the NoteEventListener.  I will have to make a note to decouple these classes later on.

That leaves two enums, NoteColors and ShareOptions, to deal with.  Since these are really just constants, I will put them under constants folder.



Now that we have the files grouped, the next step is to figure out what I want to keep, but that will be another entry.

Here is the commit for these changes :https://github.com/fsk-software/mynotes/commit/ab26f7f3bda8dd75eb6fb67bb8fb59d517810981

Update: oops!  I missed an update to one file during the last commit.  The working commit is https://github.com/fsk-software/mynotes/commit/c1665e6b4090222159cd5609e105720cc4184923