Wednesday, February 25, 2015

MyNotes: Fruit Based Libraries

As you might have noted from the last commits, I brought in the Guava library.  There are two schools of thought on Guava with Android:  Do it or Avoid at all cost.

I am ambivalent on the subject.

I don't like bringing in large libraries because they push your app towards the dreaded 65k method limit.  Android has provided ways to mitigate the issue, but I don't like getting close to it. Guava is a big library and that has to be take into consideration.

On the other hand, I don't have the time or resources to reinvent the wheel or keep it turning when it comes to the functionality that Guava gives me.

After waffling for awhile, I decided to include Guava.  This means that I will need to use Proguard ot shrink the library to only those classes that I am using.  It also means I have to be more careful in my release testing to make sure the Proguard minimazation works and that I am not including more of Guava than I need.

To bring in Guava with Gradle, you need to add MavenCentral as a valid repository and then add the dependency.  It ends up looking like this:

allprojects {
    repositories {
        jcenter()
        mavenCentral()
    }
}
...

dependencies {
    compile group: 'com.google.guava', name: 'guava', version: '18.0'

   .... other dependencies....
}

I also need to add a new file into the projects called progurard-guave.pro and add that to the release building portion of gradle:
buildTypes {
  release {
    minifyEnabled true

    // Library specific proguard files
    proguardFiles 'proguard-guava.pro'

    //Default proguard file
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  }
}

Just an FYI:  do not trust the contents of proguard-guava.pro yet.  I am saving the real work on the file for later once the development is done.

Commits

You can find the changes for this entry among the commit at https://github.com/fsk-software/mynotes/commit/a89a3c2d74d7bb5aeff7520a38d417a8ec05a9e3.

Wednesday, February 18, 2015

MyNotes: Building the Data Access Layer

Now the groundwork is laid, I can create my actual data access layer.  This basically consists of two classes : Note, and NotesManager.

Note

The Note class is a glorified POJO.  It is a very simple data object with 3 attributes:
  •  a long identifier that is defaulted to -1
  •  a non-null String text object to contain the note text.  This is defaulted to an empty String.
  •  a non-null NoteColor that is the color for the note. This defaulted to the yellow color.
It also has the associate getter and setters for each attribute.

The glorified piece comes from the two interfaces it implements: DatabaseStorable (discussed in the previous post) and Parcelable.  This makes the note aware of the Database so that it can update/delete its backing data.  The Parcelable interface means that the data can be marshalled into a Parcel.

What is Parceling?


Serialization in Android is very slow.  As a result, they created another way to marshal data in an efficient way.  It is very simple to implement, but remember that order matters.  To marshal the Note I only have two implement the writeToParcel method:

@Override
    public void writeToParcel(final Parcel dest, final int flags) {
        dest.writeLong(mId);
        dest.writeString(mText);
        dest.writeInt(mColor.ordinal());
    }

Then I implement a special constructor that takes in a Parcel object:

    public Note(Parcel source) {
        mId = source.readLong();
        mText = source.readString();
        mColor = NoteColor.getColor(source.readInt());
    }

Like I said earlier, order matters.  The order that the data is written into the Parcel is the order that it must be read back out.  No deviations.  Parcel objects can contain other Parcelable objects easily. There are complications when it comes to complex types like Maps.  The maps have to be broken down into component pieces in order to be stored.  It is then reassembled in the constructor.

I also a created some boilerplate code that is common to Parcelable objects.  It gives users of the Parcelable data more options for using the object.  That boilerplate is :

public static final Parcelable.Creator<Note> CREATOR = new Parcelable.Creator<Note>() {
        @Override
        public Note createFromParcel(final Parcel source) {
            return new Note(source);
        }


        @Override
        public Note[] newArray(final int size) {
            return new Note[0];
        }
    };



So Why Parcel?

There are a lot reasons, but the biggest is too allow the objects state to be stored in a Bundle.  This means that a copy of the object can be passed between Activities, Fragments, Services, etc via the Intent Bundle.  It also lets the object be stored in the save instance bundle in Activities and Fragments.  This will make things a lot easier when I get to the UI levels.

The Caveat

If the parcel is going to be passed in an Intent, you must watch the size carefully. It cannot exceed 1MB.  If it goes over, your app can hang and then crash.  This is due to a annoying size constraint in the OS.

Luckily, the size constraint problem does not exist if the parcel is going into a save state bundle to preserve the state of an Activity or Fragment.

I didn't mention in the database entry, but the same size issue can exist there as well.  It will let you store blobs over 1MB, but good luck on getting it back out because the Cursor class does not like to exceed that limit.

NotesManager

This is a pretty straightforward class. It is the way I will create Note objects from the database.  It provides methods to get all of the notes, or get the notes with certain colors, or get a single note.  That is pretty much it.

Commits

I did some of the development for these changes late at night after a busy week so it is broken into two commits:

Wednesday, February 11, 2015

MyNotes: Creating the Data Access Layer in the Common Library.

To start work on the data access layer I need to setup some common classes to make it easier for this app and future apps.

Manage the UI Thread

Since my access layer will be available to any area of the app, I have to worry about my threads more than I would if I was using a ContentProvider.

Prior to Lollipop, Android apps are single threaded by default.   This is often called the UI thread. However, Lollipop added a RenderThread that handles animations to make the smoother.  By default, your app will still perform all work (except animations) on the UI thread unless told to so otherwise. 

In either case, accessing the database on the UI thread is very bad.  You should never do any potentially long-lived operation on the UI thread because it will degrade your UI performance and might lead to an Android Not Responding error.

In order to prevent this, I created a class, ThreadCheck, that validates which thread is running during a method.  I will add a check to each method that access the database to verify that it is not running on the UI thread.  If it is on the UI thread, it will throw a special exception, ThreadException. This will drive out any threading issues quickly and early on.  

To check if a method is called on the UI thread is very easy.  You just have to call Looper.getMainLooper().getThread().  The MainLooper is always associated with the main thread, which happens to always be the UI thread.

Common Ways to Update Items in the Database

Now I need a common approach to updating items in the database.  This is done with an interface, DatabaseStorable, and a Utility class, DatabaseUtilities.  The DatabaseStorable contains methods to store or remove a single item from the database.  Any item that is backed by the database can implement it to update its individual content.

That interface is then used by the DatabaseUtilities to do saves/deletes on a single item or to do them in bulk in a single transaction.

Commits

I did some of the development for these changes late at night after a busy week so it is broken into two commits:

Wednesday, February 4, 2015

MyNotes: How to get the data?

Now that I have a new and improved database layer.  Now I have to figure out my primary way to access it.  My choice comes down to two options:

  • ContentProviders
  • Not ContentProviders
If you aren't familiar with ContentProviders, you can read up on them here.  They are a nice way to expose the database for manipulation, but the main use is to expose Data for manipulation by other apps.  

Since I only have a single table, the ContentProvider would map really nicely.  On the other hand, ContentProviders can be a pain to setup and get working correctly.  They can also be hard for new developers to understand.

After weighing my options, my choice came down to the decision to not expose my data beyond my app.  So I went with the non-ContentProvider option.  This doesn't preclude me from adding one in later if I change my mind about exposing the data and it simplifies some of my setup.

With that decision, I have to setup my data access layer...