Saturday, January 29, 2011

NoSQL databases - now with SQL!

So I'm writing an app and wanted to take the opportunity to see what the NoSQL buzz was all about. By no means would I need to scale to the level most programmers expect when they employ NoSQL (like Netflix) but I think I've worked with RDBMS enough (though it's been awhile). Ted Dziuba has a pretty funny critique of the NoSQL craze here.

Amazon Web Services (AWS) SimpleDB was a perfect fit - not only is it free for small fish like me but the new AWS Android SDK includes SimpleDB support. I'm not interested in writing a bunch of HTTP libraries - the AWS Android API does everything for me.

The big knock against NoSQL is its data consistency. You're not always guaranteed to get the data you're expecting. SimpleDB counters with a Consistent Read option which I'm employing. You give up a little speed but for a small app like mine it's a no-brainer. But there are no transactions to track so there's still some risk.

Another surprise was SimpleDB's support of SQl through SelectRequest. You can't do stuff like JOINs (these kinds of "advanced" operations are handled in application code) but it's convenient when you need to pull a targeted set of data.

Special shout out to the folk(s) who made sdbtool, a Firefox plug in that let's you interact with your SimpleDB account.

Here are a couple snippets from my class which handles SimpleDB interaction. Connecting is as easy as:

BasicAWSCredentials credentials;
Properties properties = new Properties();
try {
properties.load(getClass().getResourceAsStream(AWS_PROPERTIES));

String accessKeyId = properties.getProperty("accessKey");
String secretKey = properties.getProperty("secretKey");

// some boring error checking

credentials = new BasicAWSCredentials( properties.getProperty( "accessKey" ), properties.getProperty( "secretKey" ) );
// note mDB is an AmazonSimpleDBClient
mDB = new AmazonSimpleDBClient(credentials);
}

Executing queries and putting results in a List is fairly easy:

SelectRequest selectRequest = new SelectRequest("select * from accounts where m_username = '" + username + "'").withConsistentRead(true);
SelectResult selectResult = mDB.select(selectRequest);
List resultList = selectResult.getItems();

I'm able to really take advantage of the API simplicity when adding stuff to the database. NoSQL architectures seem to be pretty great for these types of actions (as long as the data gets there!).

List attributes = new ArrayList(1);
attributes.add(new ReplaceableAttribute().withName("m_username").withValue( username));
PutAttributesRequest request = new PutAttributesRequest("accounts", username, attributes);
mDB.putAttributes(request);

You know, if data consistency is critical, you could keep querying the database until your data is positively there...

Sunday, January 23, 2011

Super simple identification code

So I'm working on an Android app and I really don't care about authentication (yet) but need a way to identify a user. I can assume the user will have at least 1 google (or gmail) account and I'm also going to leverage off the Google App Engine for many services. I'll probably add in the AuthToken functionality eventually - hopefully the Authentication features of Android and Google App Engine will continue to improve in the meantime.

So here's a class that extends ListActivity:


Account[] mAccts;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// get google/gmail accounts
AccountManager acctMan = AccountManager.get(this);
mAccts = acctMan.getAccountsByType("com.google");

// put the account names into a String[]
String[] acctnames = new String[mAccts.length];
for (int i=0; i< mAccts.length; i++) {
acctnames[i] = mAccts[i].name;
}

this.setListAdapter(new ArrayAdapter(this, R.layout.accts_row, acctnames));
}


That will show the user a list of their Google accounts. Here's the onListItemClick:


super.onListItemClick(l, v, position, id);

// find the account clicked and send the intent on its way
Account acct = mAccts[position];
Intent i = new Intent(this, PayMain.class);
i.putExtra(PayMain.KEY_ACCT, acct);
startActivity(i);


In your target activity class (PayMain in this case), the account will be bundled into the Intent.

The XML files are basic for ListActivity programs. Make sure you ask for GET_ACCOUNTS permission in AndroidManifest.xml (plus USE_CREDENTIALS and INTERNET if you're going to get an AuthToken).

I ran this on my Droid X with 2 gmail accounts and it works fine. Works with no Google accounts also (says the user needs to get a Google account and try again). Having problems adding an account to the emulator. I believe I'm supposed to do it through Dev Tools but can't seem to get it to work. I'm able to add a gmail account to the email app but it's not added to the system as a real account. Plus I can't locate any good documentation of Dev Tools. Strange...

Monday, January 17, 2011

Dropbox - the way cloud apps should be

Very impressed with the functionality and ease of use of Dropbox, a revolutionary step forward in how data can be shared across multiple devices. In 4 minutes, I installed the app on my Ubuntu (Maverick Meerkat) netbook and Droid X (Froyo) phone and was passing files back and forth. I feel so stupid emailing myself just to get files from one place to another - this should resolve that problem for good. The web UI is perfect and feels a lot like a Google app. Much respect.

Sunday, January 16, 2011

And finally, Notepad Example #3

The final example changes the manner in which data is passed between the Add/Edit activity and the main activity. Instead of packing them in the extras Bundle, the data is pulled from the database. So, note my first note from the Exercise 2 entry. I failed to consider what would happen when pausing the activity for whatever reason. Here are some random thoughts:
  • Not loving the ContextMenu: Doesn't seem to be an intuitive way to access operations but I'll keep an open mind. I would prefer to offer the "Delete Note" option as a button in the NodeEdit activity.
  • Moving the SQLiteDatabase object to the NoteEdit activity makes perfect sense. I just wonder if all those reads/writes introduces risk of lag, particularly when a remote/cloud data storage solution is used.

Friday, January 14, 2011

Thoughts about Google's Notepad Example 2

So I'm not going to rewrite the Example 2 app like I did for Example 1 but here are some thoughts after going through the exercise.
  • Firing intents via startActivityForResult(): It's a little tedious packing items into the extra Bundle, especially if you have a lot of data but I'm sure it's much faster than hitting the database again.
  • Local variables versus accessing the Dalvik VM: It's included as a note in the example text, but it bears repeating, especially for mobile developers: "Accessing a local variable is much more efficient than accessing a field in the Dalvik VM, so by doing this we make only one access to the field, and five accesses to the local variable, making the routine much more efficient."
  • XML layouts are hard to debug: While the schema is pretty straightforward, it's not like there's a debugger for your XML files so any dumb mistake can make for very tedious troubleshooting.
  • Once you get a Virtual Device going in Eclipse, don't turn it off!: Upon starting up Eclipse, the AVD fires up very quickly when executing a program. But if I shut it down, do some coding or whatnot, and try to run it again, it often sits on the "Waiting for HOME ('android.process.acore') to be launched..." step. Out of habit, I sometimes kill the AVD mistakenly.

Thursday, January 13, 2011

Getting into SQLite

I grew bored drawing things on a Canvas so I moved on to the very helpful Notepad example. I like it because it's centered around the SQLite database package. Understand the importance of a good UI but the database interaction is much more my thing.

So I went through Exercise 1 then put it away and tried to code it myself. I'll spare the boring screenshots because my program doest exactly what Example 1 does - add dummy rows to a database and display them.

Couple things:
  • Got some compile errors related to Cursor stuff (specifically setListAdapter) in my main class. I was extending Activity not ListActivity. Whoops - there is a difference.
  • I like the idea of startManagingCursor and wonder why it's not default. Maybe only noobs like me use it but are people really managing their Cursor's lifecycles so thoroughly?
  • When I tried to account for SQLExceptions, Eclipse never recognized its reference even though I imported android.database.SQLException. So I just removed it. I'll come back to that one. I'm sure I'm overlooking something obvious.
  • Loving Eclipse's Ctrl-Shift-O shortcut to auto-import.
  • Took me awhile to figure out the Context data type so I could access the SQLiteOpenHelper constructor. One difference between my code and Google's example was they kept the Context around as a private variable while I just discarded it. I wonder if keeping Contexts around is useful.

Tuesday, January 4, 2011

Oh, activities need to be defined within the application?

Continue to play around with the Android SDK. I'm working on a program that makes whatever kind of shape the user requests via a menu. Yes, very advanced which is why I named it Simple App. Anyway, the app was crashing when the shape was selected so I got some hands on experience with the Eclipse debugger.

I was getting ActivityNotFoundException and it was bombing on the startActivity() call. But how can that be? The class was properly included and I declared it in AndroidManifest.xml. Well, for some reason, I added this activity outside the application tag. Rookie mistake but it wasn't self evident in the debugger.

Monday, January 3, 2011

Amazon AWS and Database.com

Much of my application development has been "data structure centric". Future projects might be in the same vein so while tinkering with Android coding, I'm looking into 2 major database products with hooks into Android (among others devices, languages, and platforms, of course).

Amazon's AWS has been a major web services provider for awhile. Their data storage product is Amazon S3 but the interesting part is the AWS SDK for Android which provides S3 storage, database creation and messaging. In fact, Amazon might have made it TOO easy to deploy mobile enterprise ("cloud") apps has this PCWorld article suggests! Once I've secured a moderate amount of Android development knowledge, I'm definitely going to open an AWS account and play around with this API (the AWS Free Usage Tier is free for a year).

Salesforce has moved into the database-as-a-service market with database.com, which as this InfoWorld article states aims to be the "back end for the entire Internet". While other companies are playing catch up, Salesforce appears heavily leveraged into the cloud computing and ASP worlds so they might be well positioned to be a database of choice for mobile developers. Unfortunately, database.com is not really live yet (their FAQ page states the full developer preview is coming out in 2011) so I guess this is the end for now.

Sunday, January 2, 2011

CNNMoney - Apple vs. Android: The view from Google

Interesting take from senior Google engineers about what the future holds for Android and iOS. The press is trying to play up an angle that these views aren't exact carbon copies of each other but they seem pretty close to me. I agree with Don Dodge that both Google and Apple can achieve their goals (Apple to continue owning the high-end market and Google to grow their software distribution by being the OS of choice for smartphone hardware makers). Perhaps a better question is "Will a third player be able to make significant inroads to the mobile OS market?". Tim Bray (in probably the best article I've read in several weeks) thinks Windows Phone 7 might make inroads and it's hard to envision Microsoft ceding such a huge market without a fight.