Archive for the ‘mobile’ category


Please think of the Users: Smarter Task Queueing/Scheduling

I’ve been using a certain Podcast application for a while, and I have it configured in such a way that it will only do updates on wifi and at 9:30 in the morning.  I have a tendency to only be connected to 3G so this leads to some pretty frustrating experiences.  Primarily, I’m getting notifications that updates couldn’t happen then I’m directed to a screen with no way of actioning on these problems.  Alright, so the software isn’t that great… but it’s sadly the best for what I need.

Though, I feel this software could be vastly improved if only the developer took a few steps to gracefully handle things such as connectivity (let’s admit it, lack of connectivity isn’t an exceptional case, it’s an expectation).  Add in configuration such as “Only download over WiFi” well now you’re going to need to elegantly handle how an update is performed.

In my app, STO on the Go I needed to perform daily updates though there’s a good chance that when the scheduled task hits the user may not have an internet connection (or only want to download updates over WiFi).  Awesomely, Android is a really loud system.  It’s yelling things **all** the time about various status changes, one of these being connectivity status changes.  I figured I would tie into this.

Tying into these services is extremely straightforward, first we need to tell our manifest that we want to listen in on some BroadcastIntents:

<receiver android:name=".receiver.ScheduleUpdateReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>

So now our <pre>ScheduleUpdateReceiver</pre> will get called each time the state of connectivity changes on the device. Keep in mind, you are going to need to keep the code as lean as possible until you are absolutely sure you need to do some heavy lifting! Nothing is more frustrating than an app that appears to be doing nothing but kills your battery.

Now it’s time for our service to actually do some stuff, this is where we will be asking a few questions.

 

public void onReceive(Context context, Intent intent) {
	ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
	TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
	String doUpdateOnNextWifiConnection = context.getString(R.string.doUpdateOnNextWifiConnection);
	SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);

	if(!prefs.getBoolean(context.getString(R.string.performDownloadsInBackground), true)) {
		// User configuration -- No background Updating
		Log.d(DEBUG_TAG, "Updates are not permitted to run. Aborting");
		return;
	}

	boolean hasActiveWifiConnection = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected();

	// Check to see if the intent that was fired was created by Android itself
	if(intent.getAction() != null && intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
		// Did the last check fail due to lack of connectivity?
		boolean performUpdateOnNextWifiConnection = prefs.getBoolean(doUpdateOnNextWifiConnection, false);
		if(performUpdateOnNextWifiConnection && hasActiveWifiConnection) {
			runUpdate(context);
			// Alright, our update has run, time to reset our state so we don't attempt to download
			// another update next time the device gets an internet connection.
			prefs.edit().putBoolean(doUpdateOnNextWifiConnection, false).commit();
		} else {  
			Log.d(DEBUG_TAG, "Update for connection to wireless access point will be ignored");
		}
	} else {
		// This is our scheduled update
		boolean canDownloadWithMobileData = prefs.getBoolean(context.getString(R.string.usenetworktype), true);
		boolean hasMobileDataConnection = (telephonyManager.getDataState() == TelephonyManager.DATA_CONNECTED);
		if((canDownloadWithMobileData && hasMobileDataConnection) || hasActiveWifiConnection) {
			runUpdate(context);
		} else {
			// So, we either don't have an internet connection or the user wasn't connected to WiFi when the scheduled
			// update was supposed to happen.
			// I chose to store this information in the shared preferences because it's pretty easy to do.  This could get
			// a little bit out of hand if you have more complex rules than what I have here.
			Log.d(DEBUG_TAG, "Cannot do a download over data and we don't have a wifi connection. On the next wifi connection, we'll do the download then");
			prefs.edit().putBoolean(doUpdateOnNextWifiConnection, true).commit();
		}
	}
}

So now we are able to handle the sort of special cases and deal with them almost immediately after a user has acquired a usable connection to the internet.


Deadline Met! STO on the Go is available on the Android Market

I gave myself a personal goal around mid to late November; to finish an STO Android app with the dataset that Phil Casgrain had given me access to.  The app is now available on the Android market as STO on the Go though it’s almost impossible to find using the search.

I’m selling the app for $1.00 though there is a good chance it will be getting an increase in the next version, which will have at least maps and favourites features.


Working with the results of NSJSONSerialization

I’ve been working on a side project at Shopify recently and one of the things I had to take a converted JSON object and store it on disk as a cache. I’m typically working with NSArrays and other fancy things so I figured this is where I’d look for serializing that data into a plist on disk.

-(BOOL) saveArray:(NSArray*)itemsArray toLocationOnDisk:(NSString*)location
{
    BOOL saved = [itemsArray writeToFile:location atomically:YES];
    return saved;
}

Because I’m targetting iOS 5 I have this nifty new tool available, it’s NSJSONSerialization though there’s a bit of a caveat. The data that you get back from it isn’t actually objects of NSArray, NSDictionary although for all intents and purposes they behave like they are in your code.

There is another way to get around this though, what you can do is convert the array into an archived object like so.

-(BOOL) saveArray:(NSArray*)itemsArray toLocationOnDisk:(NSString*)location
{
    NSData *archivedItemsArray = [NSKeyedArchiver archivedDataWithRootObject:itemsArray];
    BOOL saved = [archivedItemsArray writeToFile:location atomically:YES];
    return saved;
}

Now all we need to do is re-convert that data into an NSArray, which is relatively straightforward.

// Deserialize the object back to an NSArray
-(NSArray*) getArrayFromDisk:(NSString*)location
{
    NSData *rawData = [NSData dataWithContentsOfFile:location];
    if(rawData == nil)
        // Assuming iOS 5 using ARC
        return [[NSArray alloc] init];
    return (NSArray*) [NSKeyedUnarchiver unarchiveObjectWithData:rawData];
}

Once you know about this, it’s pretty straightforward but trying to find answers on sites like StackOverflow for this kind of problem is a bit tricky since people often assume you are working with plain old NSArrays and such.


Lessons Learned from Bulk Parsing and Database Insertion

I’m beginning to work on an STO application from an API that was created by Philippe Casgrain.  The data was stored in a pretty big JSON file, and I decided that instead of breaking it into smaller pieces I would simply insert everything into an SQLite database.  Previously the only time I had worked with Android databases had simply been via insertions with ContentValues, which is a lot slower than I had thought at first.

Previously this is what I was doing

void insertData(List objects, SQLiteDatabase db) { 
    ContentValues cvs = new ContentValues();
    for(Foo obj : objects){
        cvs.put("FooStringColumn", obj.fooString());
        cvs.put("FooIntegerColumn", obj.fooInteger()); 
        long result = db.insertWithOnConflict("Foo", null, cvs, SQLiteDatabase.CONFLICT_REPLACE);
    }
}

This works alright, though when you are generating thousands of entries from your JSON data it results in something that’s so slow it’s painful. At first I thought my problems were stemming from using the org.json tools included in Android so I switched over to using Google GSON instead, which did help reduce a ton of unnecessary garbage collection. Though, everything was still slow.

My database knowledge isn’t extremely deep, and I recall being able to compile PreparedStatements to speed up interaction with the DB. After a bit of searching on the internet I came across an alternative way of doing database insertion using this thing known as an InsertHelper. Using an InsertHelper is pretty straightforward, though it requires writing a bit more code than ContentValues, but it’s way faster.

void insertData(List objects, SQLiteDatabase db){
    InsertHelper helper = new InsertHelper(db, "Foo");
    final int fooStrCol = helper.getColumnIndex("FooStringColumn");
    final int fooIntCol = helper.getColumnIndex("FooIntegerColumn");
    for(Foo obj : objects){
        helper.prepareForInsert();
        
        helper.bind(fooStrCol, obj.fooString());
        helper.bind(fooIntCol, obj.fooInteger());

        helper.execute();
    }
}

To also help speed things up, I extracted all of my data first then inserted everything in a transaction. This helped reduce overhead and I was able to get the database initialized in about 10 seconds. Surely I can speed it up further, but for now this seems to solve my problems.

References


Shopify API for Android coming out soon

Last week at Shopify we had a this thing called FedEx Days (or something similar) where we were given 2 days to work on any project we wanted.  After having looked at the Jhopify library, and trying to patch it, I figured that API bindings for Shopify could be solved better.  I had worked with the Shopify API before when I first started working at Shopify while I was still doing Android dev there.  Since then though, nothing really came of it.

I had taken a few lessons from that experience and decided to use that knowledge to create a tool so that Android devs could spend less time writing boilerplate API code, and more time solving problems.  I also wanted to ensure that I could provide as much of a one-to-one mapping to the API as possible.  This meant one thing, Java Beans.  I looked at the API and looked at a blank Article.java file and cringed.  There has to be a better way to do this; and of course there is!  You see, I remembered reading something from the Pragmatic Programmer.  It’s something along the lines of “If you have to write repetitive garbage, why not have a computer do it instead? Voila! Code Generators!”.

Thankfully, the Shopify API provides some pretty good example output and I figured I would use this as a tool.  With the Shopify examples that I had so gracefully copy-pasta’d into some ‘fixtures’ that I was intending on using for tests I then proceeded to use them as training data.

So I fired up my default system text editor (TextMate, though emacs would’ve been preferable… no time!) and started hacking out some ruby.  First step was to get all the POJOs/beans written up, then I’d tackle actually getting the API to work.  This was pretty straightforward; read in the data, turn it into a hash, infer the data types and apply the various private members and their getters/setters, add annotations, etc.

But it dawned on me.  What if the Shopify API for say, Articles were to ever change? I could just manually add the new changes, but that sucks.  This reminded me of another problem I had when doing some iOS/core data work about a year ago which has much of the same problem, which was solved.  The tool that solved the iOS problem is known as MOGenerator.  The way the tool works is by inspecting your data model and creating intermediate classes with all the boilerplate, then adds a subclass where you can add custom code.  It makes the promise that if you ever put custom code in the _yourModel (or whatever syntax it uses), MOGenerator will gladly come in and overwrite all of it.  So I figured that taking a similar approach for the Shopify models would be fine, and would also save a bunch of time/worry.

With all that working and tests running green on some simple and more complex data types, I then proceeded to create the API bindings.  I decided to go with a tool called CRest which makes mapping API endpoints far simpler.  After writing the first endpoint I again realized that this could be generated as well, mind you not as elegantly.  Not all endpoints map out in a manner that is as simple as the beans, but I figured this is the best way to get at least some form of API wrapper working.  So making some really basic assumptions, I also generated all the endpoints.  These probably won’t work as elegantly as the beans did, but it should be a starting point for anyone wanting to work with the API.

So all in all, I was able to get hundreds of lines of code written up in about 200 lines of ruby.  Though we need to keep in mind that much of that ruby code consists of huge blocks of text and not actual logic.  If I were to remove all of that, I’d say this was accomplished in even fewer lines, perhaps 100?  I’m hoping to have the code publicly available on GitHub soon.  Just need to get a tutorial/demo app written up, unless you don’t care, then I may be able to convince some people to release it as is.


Looking for Work

I’m going to be available for employment within the near future. If you are interested in any skills I have to offer or feel that I may be a good fit on your team, please feel free to contact me.

I have a resume up on StackOverflow where you can get more information about what skills I have and to learn a bit more about me if you’d like.


STO on the Go is Live

Earlier last week I was trying to view the bus schedule from my device. Unfortunately, I have a T-Mobile Nexus one on a Rogers network; so EDGE speeds only. The website for the buses I take is pretty much image driven, so pages take forever to load. And even when things do load, sometimes opening up the links doesn’t work (don’t even try on a BlackBerry!).

I’d had enough of it and figured I would look into getting a mobile web version that would be extremely light that provides all the functionality you would need to find out what are the timings for the bus route you want. Now, the application does still have some bugs in it which mainly have to do with my poor AJAX and jQuery skills but it does do the job.

You can access the site by visiting http://stoonthego.appspot.com. I’ve tested it on the iPhone, Android and Blackberry and it works pretty well. There are some issues with the clicking of stops on a BlackBerry, but there is a fix which is achieved by moving your cursor to the top of the screen then mousing over each item. When you get the ][ symbol click and you should be brought to the bus listing for that stop.

If I have some time over the next few weeks I’ll work on it some more to style it a bit so it will actually look good on a mobile device as well as increase the hit zones for everything to make the interface easier to interact with. I also intend on plugging into it to provide a native Android application that will allow you to cache everything on disk in order to reduce network usage. Maybe even allow configuration of caching based on what kind of connection you are on.

If you’ve given it a shot, please leave me your comments about how the experience was as well as what kind of device you were using.

Edit

Since the STO has recently changed their travel planner, it is unfortunate that the changes have effected the STO on the Go site. Because of how the new planner works, it will not be worth the effort to try and fix which is rather unfortunate since the new site is very unfriendly towards mobile devices.